<?php

namespace Tests\Feature;

use App\Models\ExportProFile;
use App\Models\Label;
use App\Models\Service;
use App\Models\ServiceAgendaItem;
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\ProPlaylistReader;
use Tests\TestCase;

final class ExportProFileKeywordInjectionTest extends TestCase
{
    use RefreshDatabase;

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

    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 - '.$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 addSongAgendaItem(Service $service, Song $song, string $title, int $sortOrder): void
    {
        $serviceSong = ServiceSong::create([
            'service_id' => $service->id,
            'song_id' => $song->id,
            'cts_song_name' => $song->title,
            'order' => $sortOrder,
        ]);

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

    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);
    }

    public function test_keyword_datei_wird_direkt_nach_passendem_ablaufpunkt_eingefuegt(): void
    {
        $service = Service::factory()->create([
            'title' => 'Keyword Service',
            'date' => now(),
        ]);

        // Uppercase title vs lowercase keyword proves case-insensitive substring match.
        $this->addSongAgendaItem($service, $this->createSongWithContent('Abendmahlslied'), 'ABENDMAHL feiern', 1);
        $this->addSongAgendaItem($service, $this->createSongWithContent('Predigtlied'), 'Predigt', 2);

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

        ExportProFile::create([
            'type' => 'keyword',
            'keyword' => 'abendmahl',
            'original_name' => 'kommunion.pro',
            'stored_path' => $storedPath,
            'order' => 1,
        ]);

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

        $entryNames = array_map(fn ($e) => $e->getName(), $playlist->getEntries());

        $abendmahlPos = array_search('Abendmahlslied', $entryNames, true);
        $predigtPos = array_search('Predigtlied', $entryNames, true);
        $kommunionPositions = array_keys($entryNames, 'kommunion', true);

        $this->assertNotFalse($abendmahlPos, 'Abendmahl song entry not found');
        $this->assertNotFalse($predigtPos, 'Predigt song entry not found');
        $this->assertCount(1, $kommunionPositions, 'Keyword presentation must be injected exactly once');

        $kommunionPos = $kommunionPositions[0];
        $this->assertSame($abendmahlPos + 1, $kommunionPos, 'Keyword presentation must appear immediately after the matched item');
        $this->assertLessThan($predigtPos, $kommunionPos, 'Keyword presentation must not appear after the non-matching item');

        $embeddedFiles = $playlist->getEmbeddedFiles();
        $this->assertArrayHasKey('KEYWORD_1_kommunion.pro', $embeddedFiles);
        $this->assertSame('kommunion-pro-bytes', $embeddedFiles['KEYWORD_1_kommunion.pro']);

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

    public function test_leeres_keyword_wird_nicht_injiziert(): void
    {
        $service = Service::factory()->create([
            'title' => 'Kein Keyword Service',
            'date' => now(),
        ]);

        $this->addSongAgendaItem($service, $this->createSongWithContent('Abendmahlslied'), 'Abendmahl feiern', 1);

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

        ExportProFile::create([
            'type' => 'keyword',
            'keyword' => '',
            'original_name' => 'leer.pro',
            'stored_path' => $storedPath,
            'order' => 1,
        ]);

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

        $entryNames = array_map(fn ($e) => $e->getName(), $playlist->getEntries());

        $this->assertNotContains('leer', $entryNames, 'Files with an empty keyword must never be injected');

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