<?php

namespace Tests\Feature;

use App\Models\Label;
use App\Models\Service;
use App\Models\ServiceAgendaItem;
use App\Models\ServiceSong;
use App\Models\Slide;
use App\Models\Song;
use App\Services\PlaylistExportService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Storage;
use ProPresenter\Parser\ProPlaylistReader;
use Tests\Support\InspectsSlideFillMedia;
use Tests\TestCase;

final class KeyVisualFallbackTest extends TestCase
{
    use InspectsSlideFillMedia;
    use RefreshDatabase;

    protected function setUp(): void
    {
        parent::setUp();

        Storage::fake('public');
    }

    public function test_non_song_agenda_item_without_slides_becomes_headline(): void
    {
        Storage::disk('public')->put('slides/keyvisual.jpg', 'keyvisual-image');

        $service = Service::factory()->create([
            'title' => 'Keyvisual Service',
            'date' => now(),
            'key_visual_filename' => 'slides/keyvisual.jpg',
        ]);

        ServiceAgendaItem::factory()->create([
            'service_id' => $service->id,
            'title' => 'Begrüßung',
            'service_song_id' => null,
            'sort_order' => 1,
            'is_before_event' => false,
        ]);

        $slideCountBefore = Slide::count();

        $result = app(PlaylistExportService::class)->generatePlaylist($service);
        $playlist = ProPlaylistReader::read($result['path']);

        // Content-less item before any real content → HEADER playlist item (no embedded .pro
        // of its own). The only embedded .pro is the trailing looping Abspann key-visual.
        $proFiles = $playlist->getEmbeddedProFiles();
        $this->assertCount(1, $proFiles);
        $this->assertStringStartsWith('Abspann-', array_key_first($proFiles));
        $this->assertSame($slideCountBefore, Slide::count());

        // Playlist has a header entry named 'Begrüßung'
        $headerEntry = null;
        foreach ($playlist->getEntries() as $entry) {
            if ($entry->isHeader() && $entry->getName() === 'Begrüßung') {
                $headerEntry = $entry;
                break;
            }
        }
        $this->assertNotNull($headerEntry, 'Expected a HEADER playlist entry for Begrüßung');

        // The key-visual is embedded via the trailing Abspann presentation.
        $this->assertArrayHasKey('KEY_VISUAL.jpg', $playlist->getEmbeddedMediaFiles());

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

    public function test_song_agenda_item_does_not_get_keyvisual_fallback(): void
    {
        Storage::disk('public')->put('slides/keyvisual.jpg', 'keyvisual-image');

        $service = Service::factory()->create([
            'title' => 'Song Service',
            'date' => now(),
            'key_visual_filename' => 'slides/keyvisual.jpg',
        ]);
        $song = $this->createSongWithContent('Nur ein Lied');
        $serviceSong = ServiceSong::create([
            'service_id' => $service->id,
            'song_id' => $song->id,
            'cts_song_name' => 'Nur ein Lied',
            'order' => 1,
        ]);

        ServiceAgendaItem::factory()->create([
            'service_id' => $service->id,
            'title' => 'Nur ein Lied',
            'service_song_id' => $serviceSong->id,
            'sort_order' => 1,
            'is_before_event' => false,
        ]);

        $result = app(PlaylistExportService::class)->generatePlaylist($service);
        $playlist = ProPlaylistReader::read($result['path']);

        // The song .pro plus the trailing looping Abspann key-visual presentation.
        $this->assertCount(2, $playlist->getEmbeddedProFiles());
        $this->assertNotNull($playlist->getEmbeddedSong('Nur ein Lied.pro'));
        $this->assertNull($playlist->getEmbeddedSong('Keyvisual.pro'));

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

    public function test_sermon_agenda_item_with_uploaded_slides_prepends_keyvisual_sequence(): void
    {
        Storage::disk('public')->put('slides/keyvisual.jpg', 'keyvisual-image');
        Storage::disk('public')->put('slides/sermon.jpg', 'sermon-image');

        $service = Service::factory()->create([
            'title' => 'Slides Service',
            'date' => now(),
            'key_visual_filename' => 'slides/keyvisual.jpg',
            'preacher_name' => 'Pastor Paul',
            'preacher_name_override' => null,
        ]);
        $agendaItem = ServiceAgendaItem::factory()->create([
            'service_id' => $service->id,
            'title' => 'Predigt',
            'service_song_id' => null,
            'sort_order' => 1,
            'is_before_event' => false,
        ]);

        Slide::factory()->create([
            'service_id' => $service->id,
            'service_agenda_item_id' => $agendaItem->id,
            'type' => 'sermon',
            'original_filename' => 'sermon.jpg',
            'stored_filename' => 'slides/sermon.jpg',
            'sort_order' => 0,
        ]);

        $result = app(PlaylistExportService::class)->generatePlaylist($service);
        $playlist = ProPlaylistReader::read($result['path']);
        $sermonSong = $playlist->getEmbeddedSong('Predigt.pro');

        // Keyvisual-Predigt intro + Predigt sermon slides + trailing looping Abspann.
        $this->assertCount(3, $playlist->getEmbeddedProFiles());
        $this->assertNotNull($sermonSong);

        $names = array_map(fn ($entry) => $entry->getName(), $playlist->getEntries());
        $this->assertContains('Keyvisual-Predigt', $names);
        $this->assertLessThan(
            array_search('Predigt', $names, true),
            array_search('Keyvisual-Predigt', $names, true),
        );

        $slides = $this->allParserSlides($sermonSong);
        $this->assertCount(1, $slides);
        // Sermon slide is a foreground content image; no service background configured → no background layer.
        $this->assertFalse($slides[0]->hasBackgroundMedia());
        $this->assertNotContains('BACKGROUND.jpg', $this->fillMediaUrls($slides[0]));
        $this->assertNotEmpty($this->fillMediaUrls($slides[0]));
        $this->assertFalse($this->hasImageMediaAction($slides[0]));

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

    public function test_empty_non_song_item_before_content_becomes_headline(): void
    {
        $service = Service::factory()->create([
            'title' => 'Ohne Keyvisual',
            'date' => now(),
            'key_visual_filename' => null,
        ]);
        $song = $this->createSongWithContent('Vorhandenes Lied');
        $serviceSong = ServiceSong::create([
            'service_id' => $service->id,
            'song_id' => $song->id,
            'cts_song_name' => 'Vorhandenes Lied',
            'order' => 1,
        ]);

        ServiceAgendaItem::factory()->create([
            'service_id' => $service->id,
            'title' => 'Begrüßung ohne Folien',
            'service_song_id' => null,
            'sort_order' => 1,
            'is_before_event' => false,
        ]);
        ServiceAgendaItem::factory()->create([
            'service_id' => $service->id,
            'title' => 'Vorhandenes Lied',
            'service_song_id' => $serviceSong->id,
            'sort_order' => 2,
            'is_before_event' => false,
        ]);

        $result = app(PlaylistExportService::class)->generatePlaylist($service);
        $playlist = ProPlaylistReader::read($result['path']);
        $embeddedProFiles = $playlist->getEmbeddedProFiles();

        // Content-less item before real content → HEADER playlist item (no embedded .pro for headline)
        // Only the song .pro is embedded
        $this->assertCount(1, $embeddedProFiles);
        $this->assertNotNull($playlist->getEmbeddedSong('Vorhandenes Lied.pro'));

        // Playlist has a header entry named 'Begrüßung ohne Folien'
        $headerEntry = null;
        foreach ($playlist->getEntries() as $entry) {
            if ($entry->isHeader() && $entry->getName() === 'Begrüßung ohne Folien') {
                $headerEntry = $entry;
                break;
            }
        }
        $this->assertNotNull($headerEntry, 'Expected a HEADER playlist entry for Begrüßung ohne Folien');

        // No KEY_VISUAL.jpg embedded (no keyvisual configured)
        $this->assertArrayNotHasKey('KEY_VISUAL.jpg', $playlist->getEmbeddedMediaFiles());

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

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

        $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' => 'Erste Zeile']);

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

        return $song;
    }

    private function allParserSlides(\ProPresenter\Parser\Song $parserSong): array
    {
        $slides = [];

        foreach ($parserSong->getGroups() as $group) {
            foreach ($parserSong->getSlidesForGroup($group) as $slide) {
                $slides[] = $slide;
            }
        }

        return $slides;
    }

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

        $items = scandir($dir);
        if ($items === false) {
            return;
        }

        foreach ($items as $item) {
            if ($item === '.' || $item === '..') {
                continue;
            }

            $path = $dir.'/'.$item;
            is_dir($path) ? $this->cleanupTempDir($path) : unlink($path);
        }

        rmdir($dir);
    }
}
