<?php

declare(strict_types=1);

namespace App\Framework\LiveComponents\Profiling\ValueObjects;

use App\Framework\Core\ValueObjects\Byte;
use App\Framework\Core\ValueObjects\Duration;
use App\Framework\Core\ValueObjects\Timestamp;

/**
 * Profile Result Value Object
 *
 * Immutable result of a completed profiling session.
 */
final readonly class ProfileResult
{
    /**
     * @param ProfileSessionId $sessionId Session identifier
     * @param string $componentId Component ID
     * @param Duration $totalDuration Total session duration
     * @param Byte $totalMemory Total memory used
     * @param array<ProfilePhase> $phases All lifecycle phases
     * @param array<MemorySnapshot> $memorySnapshots All memory snapshots
     * @param Timestamp $startTime Session start time
     * @param Timestamp $endTime Session end time
     */
    public function __construct(
        public ProfileSessionId $sessionId,
        public string $componentId,
        public Duration $totalDuration,
        public Byte $totalMemory,
        public array $phases,
        public array $memorySnapshots,
        public Timestamp $startTime,
        public Timestamp $endTime
    ) {
    }

    /**
     * Get total duration in milliseconds
     */
    public function getTotalDurationMs(): float
    {
        return $this->totalDuration->toMilliseconds();
    }

    /**
     * Get total memory in megabytes
     */
    public function getTotalMemoryMB(): float
    {
        return $this->totalMemory->toMegabytes(2);
    }

    /**
     * Get phase by name
     */
    public function getPhase(string $name): ?ProfilePhase
    {
        foreach ($this->phases as $phase) {
            if ($phase->name === $name) {
                return $phase;
            }
        }

        return null;
    }

    /**
     * Get memory snapshot by label
     */
    public function getSnapshot(string $label): ?MemorySnapshot
    {
        foreach ($this->memorySnapshots as $snapshot) {
            if ($snapshot->label === $label) {
                return $snapshot;
            }
        }

        return null;
    }

    /**
     * Export as Flamegraph format
     *
     * Generates Brendan Gregg's Flamegraph format for visualization.
     * Format: function_name;parent_name count
     */
    public function exportFlamegraph(): string
    {
        $output = [];

        // Build call stack representation
        $baseStack = "livecomponent.{$this->componentId}";

        foreach ($this->phases as $phase) {
            $stack = "{$baseStack};{$phase->name}";
            $samples = (int) ceil($phase->getDurationMs()); // Convert ms to sample count

            $output[] = "{$stack} {$samples}";
        }

        return implode("\n", $output);
    }

    /**
     * Export as Timeline format for DevTools
     *
     * Generates Chrome DevTools Performance Timeline compatible format.
     */
    public function exportTimeline(): array
    {
        $events = [];
        $currentTime = $this->startTime->toFloat() * 1000; // Convert to microseconds

        foreach ($this->phases as $phase) {
            $events[] = [
                'name' => $phase->name,
                'cat' => 'livecomponent',
                'ph' => 'X', // Complete event
                'ts' => $currentTime,
                'dur' => $phase->getDurationMs() * 1000, // Convert ms to microseconds
                'pid' => 1,
                'tid' => 1,
                'args' => [
                    'component_id' => $this->componentId,
                    'memory_delta_mb' => $phase->getMemoryMB(),
                    ...$phase->attributes,
                ],
            ];

            $currentTime += $phase->getDurationMs() * 1000;
        }

        // Add memory snapshots as instant events
        foreach ($this->memorySnapshots as $snapshot) {
            $events[] = [
                'name' => "memory.{$snapshot->label}",
                'cat' => 'livecomponent',
                'ph' => 'i', // Instant event
                'ts' => $snapshot->timestamp->toFloat() * 1000000,
                's' => 'g', // Global scope
                'pid' => 1,
                'tid' => 1,
                'args' => [
                    'current_mb' => $snapshot->getCurrentMemoryMB(),
                    'peak_mb' => $snapshot->getPeakMemoryMB(),
                    'allocated_objects' => $snapshot->allocatedObjects,
                ],
            ];
        }

        return $events;
    }

    /**
     * Convert to array
     */
    public function toArray(): array
    {
        return [
            'session_id' => $this->sessionId->toString(),
            'component_id' => $this->componentId,
            'total_duration_ms' => $this->getTotalDurationMs(),
            'total_memory_mb' => $this->getTotalMemoryMB(),
            'start_time' => $this->startTime->toIso8601(),
            'end_time' => $this->endTime->toIso8601(),
            'phases' => array_map(fn($phase) => $phase->toArray(), $this->phases),
            'memory_snapshots' => array_map(fn($snapshot) => $snapshot->toArray(), $this->memorySnapshots),
        ];
    }
}
