<?php

declare(strict_types=1);

namespace App\Framework\Http\Streaming;

final class AdaptivePlaylist
{
    private array $representations = [];

    private array $segments = [];

    public function __construct(
        private readonly string $videoId,
        private readonly PlaylistType $type = PlaylistType::MASTER
    ) {
    }

    public function addRepresentation(
        string $id,
        int $bandwidth,
        string $resolution = '',
        string $codecs = '',
        string $mimeType = 'video/mp4'
    ): self {
        $this->representations[] = new StreamRepresentation(
            $id,
            $bandwidth,
            $resolution,
            $codecs,
            $mimeType
        );

        return $this;
    }

    public function addSegment(string $uri, float $duration, ?int $sequence = null): self
    {
        $this->segments[] = [
            'uri' => $uri,
            'duration' => $duration,
            'sequence' => $sequence ?? count($this->segments),
        ];

        return $this;
    }

    public function generate(StreamingFormat $format): string
    {
        return match ($format) {
            StreamingFormat::HLS => $this->generateHls(),
            StreamingFormat::DASH => $this->generateDash()
        };
    }

    private function generateHls(): string
    {
        if ($this->type === PlaylistType::MASTER) {
            return $this->generateHlsMaster();
        }

        return $this->generateHlsMedia();
    }

    private function generateDash(): string
    {
        return $this->generateDashManifest();
    }

    private function generateHlsMaster(): string
    {
        $playlist = "#EXTM3U\n#EXT-X-VERSION:3\n";

        foreach ($this->representations as $rep) {
            $playlist .= "#EXT-X-STREAM-INF:BANDWIDTH={$rep->bandwidth}";
            if ($rep->resolution) {
                $playlist .= ",RESOLUTION={$rep->resolution}";
            }
            if ($rep->codecs) {
                $playlist .= ",CODECS=\"{$rep->codecs}\"";
            }
            $playlist .= "\n{$rep->id}.m3u8\n";
        }

        return $playlist;
    }

    private function generateHlsMedia(): string
    {
        $playlist = "#EXTM3U\n#EXT-X-VERSION:3\n";
        $playlist .= "#EXT-X-TARGETDURATION:10\n";
        $playlist .= "#EXT-X-MEDIA-SEQUENCE:0\n";

        foreach ($this->segments as $segment) {
            $playlist .= "#EXTINF:{$segment['duration']},\n";
            $playlist .= "{$segment['uri']}\n";
        }

        $playlist .= "#EXT-X-ENDLIST\n";

        return $playlist;
    }

    private function generateDashManifest(): string
    {
        $xml = '<?xml version="1.0" encoding="utf-8"?>' . "\n";
        $xml .= '<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" ';
        $xml .= 'type="static" mediaPresentationDuration="PT0H10M0S" ';
        $xml .= 'minBufferTime="PT2S" profiles="urn:mpeg:dash:profile:isoff-main:2011">' . "\n";

        $xml .= '<Period>' . "\n";
        $xml .= '<AdaptationSet mimeType="video/mp4" codecs="avc1.64001f">' . "\n";

        foreach ($this->representations as $rep) {
            $xml .= '<Representation id="' . $rep->id . '" ';
            $xml .= 'bandwidth="' . $rep->bandwidth . '" ';
            if ($rep->resolution) {
                [$width, $height] = explode('x', $rep->resolution);
                $xml .= 'width="' . $width . '" height="' . $height . '" ';
            }
            $xml .= 'codecs="' . $rep->codecs . '">' . "\n";
            $xml .= '<BaseURL>' . $rep->id . '/</BaseURL>' . "\n";
            $xml .= '<SegmentList>' . "\n";

            // Segments hinzufügen
            foreach ($this->segments as $segment) {
                $xml .= '<SegmentURL media="' . $segment['uri'] . '"/>' . "\n";
            }

            $xml .= '</SegmentList>' . "\n";
            $xml .= '</Representation>' . "\n";
        }

        $xml .= '</AdaptationSet>' . "\n";
        $xml .= '</Period>' . "\n";
        $xml .= '</MPD>';

        return $xml;
    }

    public function getRepresentations(): array
    {
        return $this->representations;
    }

    public function getSegments(): array
    {
        return $this->segments;
    }
}
