<?php

namespace Tests\Feature;

use App\Models\ExportProFile;
use App\Models\Label;
use App\Models\Service;
use App\Models\ServiceSong;
use App\Models\Song;
use App\Services\PlaylistExportService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Storage;
use ProPresenter\Parser\PresentationBundle;
use ProPresenter\Parser\ProBundleWriter;
use ProPresenter\Parser\ProFileGenerator;
use Tests\TestCase;

/**
 * FIX 3: A pre-added .probundle (prefix/postfix ExportProFile) must be unpacked
 * with the parser's ProBundleReader (Zip64-aware) so the embedded .pro bytes are
 * read correctly and the presentation appears in the exported playlist.
 */
final class ExportPreAddedProBundleTest extends TestCase
{
    use RefreshDatabase;

    protected function setUp(): void
    {
        parent::setUp();
        Storage::fake('public');
    }

    private function createSongWithContent(string $title = 'Test Song'): Song
    {
        $song = Song::create([
            'title' => $title,
            'ccli_id' => fake()->unique()->numerify('#####'),
            'author' => 'Test Author',
        ]);

        $label = Label::firstOrCreate(['name' => 'Verse 1 - '.$title], ['color' => '#2196F3']);
        $section = $song->sections()->create(['label_id' => $label->id, 'order' => 0]);
        $section->slides()->create(['order' => 0, 'text_content' => 'Inhalt']);

        $arrangement = $song->arrangements()->create(['name' => 'normal', 'is_default' => true]);
        $arrangement->arrangementSections()->create(['song_section_id' => $section->id, 'order' => 0]);

        return $song;
    }

    /** Build a minimal valid .probundle and register it as a prefix ExportProFile on the local disk. */
    private function registerPrefixBundle(string $proName = 'IntroBundle'): ExportProFile
    {
        $song = ProFileGenerator::generate(
            $proName,
            [[
                'name' => 'Intro',
                'color' => [0, 0, 0, 1],
                'slides' => [['text' => 'Willkommen']],
            ]],
            [['name' => 'normal', 'groupNames' => ['Intro']]],
        );

        $bundle = new PresentationBundle($song, $proName.'.pro', []);

        $tmp = tempnam(sys_get_temp_dir(), 'fixture-').'.probundle';
        ProBundleWriter::write($bundle, $tmp);
        $bytes = file_get_contents($tmp);
        @unlink($tmp);

        $storedPath = 'export-pro-files/'.$proName.'.probundle';
        Storage::disk('local')->put($storedPath, $bytes);

        return ExportProFile::create([
            'type' => 'prefix',
            'original_name' => $proName.'.probundle',
            'stored_path' => $storedPath,
            'order' => 1,
        ]);
    }

    public function test_vorab_hinzugefuegtes_probundle_ergibt_nicht_leere_playlist(): void
    {
        $service = Service::factory()->create(['finalized_at' => now(), 'title' => 'Mit Prefix']);
        $song = $this->createSongWithContent('Hauptlied');

        ServiceSong::create([
            'service_id' => $service->id,
            'song_id' => $song->id,
            'cts_song_name' => 'Hauptlied',
            'order' => 1,
        ]);

        $this->registerPrefixBundle('IntroBundle');

        $capturedItems = [];
        $capturedFiles = [];

        $exportService = new class($capturedItems, $capturedFiles) extends PlaylistExportService
        {
            /** @var array<int, array> */
            private array $items;

            /** @var array<string, string> */
            private array $files;

            public function __construct(array &$items, array &$files)
            {
                parent::__construct(app(\App\Services\MacroResolutionService::class));
                $this->items = &$items;
                $this->files = &$files;
            }

            protected function writeProFile(string $path, string $name, array $groups, array $arrangements, array $options = []): void
            {
                file_put_contents($path, 'mock-pro:'.$name);
            }

            protected function writePlaylistFile(string $path, string $name, array $items, array $embeddedFiles): void
            {
                $this->items = $items;
                $this->files = $embeddedFiles;
                file_put_contents($path, 'mock-playlist:'.$name);
            }
        };

        $result = $exportService->generatePlaylist($service);

        $this->assertFileExists($result['path']);

        // The prefix .pro must be present as a playlist item and embedded with non-empty bytes.
        $prefixItem = collect($capturedItems)->first(
            fn ($item) => str_starts_with($item['path'] ?? '', 'PREFIX_') && str_ends_with($item['path'], '.pro')
        );

        $this->assertNotNull($prefixItem, 'Pre-added .probundle should produce a PREFIX_*.pro playlist item.');

        $embeddedKey = $prefixItem['path'];
        $this->assertArrayHasKey($embeddedKey, $capturedFiles);
        $this->assertNotSame('', $capturedFiles[$embeddedKey], 'Embedded .pro from .probundle must be non-empty.');
        $this->assertGreaterThan(0, strlen($capturedFiles[$embeddedKey]));

        $this->cleanupTempDir($result['temp_dir']);
    }

    private function cleanupTempDir(string $dir): void
    {
        if (! is_dir($dir)) {
            return;
        }

        foreach (scandir($dir) as $item) {
            if ($item === '.' || $item === '..') {
                continue;
            }
            $path = $dir.'/'.$item;
            is_dir($path) ? $this->cleanupTempDir($path) : unlink($path);
        }
        rmdir($dir);
    }
}
