<?php

use App\Models\Service;
use App\Models\ServiceAgendaItem;
use App\Models\ServiceSong;
use App\Models\Setting;
use App\Models\Slide;
use App\Models\Song;
use App\Models\SongArrangement;
use App\Models\User;
use Carbon\Carbon;

/*
|--------------------------------------------------------------------------
| Finalization Tests
|--------------------------------------------------------------------------
*/

beforeEach(function () {
    Carbon::setTestNow('2026-03-01 10:00:00');
    $this->user = User::factory()->create();
});

test('finalize ohne voraussetzungen gibt warnungen zurueck (legacy)', function () {
    $service = Service::factory()->create(['finalized_at' => null]);

    // Song without match or arrangement (legacy service_songs)
    ServiceSong::create([
        'service_id' => $service->id,
        'song_id' => null,
        'song_arrangement_id' => null,
        'use_translation' => false,
        'order' => 1,
        'cts_song_name' => 'Test Song',
        'cts_ccli_id' => '12345',
    ]);

    $response = $this->actingAs($this->user)
        ->postJson(route('services.finalize', $service), ['confirmed' => false]);

    $response->assertOk()
        ->assertJson([
            'needs_confirmation' => true,
        ]);

    $data = $response->json();
    expect($data['warnings'])->toHaveCount(3)
        ->and($data['warnings'][0])->toContain('Songs sind zugeordnet')
        ->and($data['warnings'][1])->toContain('Arrangement')
        ->and($data['warnings'][2])->toContain('Predigtfolien');

    // Not finalized yet
    expect($service->fresh()->finalized_at)->toBeNull();
});

test('finalize mit confirmed=true trotz warnungen finalisiert service', function () {
    $service = Service::factory()->create(['finalized_at' => null]);

    ServiceSong::create([
        'service_id' => $service->id,
        'song_id' => null,
        'song_arrangement_id' => null,
        'use_translation' => false,
        'order' => 1,
        'cts_song_name' => 'Test Song',
        'cts_ccli_id' => '12345',
    ]);

    $response = $this->actingAs($this->user)
        ->postJson(route('services.finalize', $service), ['confirmed' => true]);

    $response->assertOk()
        ->assertJson([
            'needs_confirmation' => false,
            'success' => 'Service wurde abgeschlossen.',
        ]);

    expect($service->fresh()->finalized_at)->not->toBeNull();
});

test('finalize ohne warnungen finalisiert direkt', function () {
    $service = Service::factory()->create(['finalized_at' => null]);

    $song = Song::factory()->create();
    $arrangement = SongArrangement::factory()->create(['song_id' => $song->id]);

    ServiceSong::create([
        'service_id' => $service->id,
        'song_id' => $song->id,
        'song_arrangement_id' => $arrangement->id,
        'use_translation' => false,
        'order' => 1,
        'cts_song_name' => 'Test Song',
        'cts_ccli_id' => '12345',
    ]);

    Slide::factory()->create([
        'service_id' => $service->id,
        'type' => 'sermon',
    ]);

    $response = $this->actingAs($this->user)
        ->postJson(route('services.finalize', $service), ['confirmed' => false]);

    $response->assertOk()
        ->assertJson([
            'needs_confirmation' => false,
            'success' => 'Service wurde abgeschlossen.',
        ]);

    expect($service->fresh()->finalized_at)->not->toBeNull();
});

test('finalize warnt bei fehlenden song-zuordnungen', function () {
    $service = Service::factory()->create(['finalized_at' => null]);

    $song = Song::factory()->create();
    $arrangement = SongArrangement::factory()->create(['song_id' => $song->id]);

    // One matched, one unmatched
    ServiceSong::create([
        'service_id' => $service->id,
        'song_id' => $song->id,
        'song_arrangement_id' => $arrangement->id,
        'use_translation' => false,
        'order' => 1,
        'cts_song_name' => 'Matched',
        'cts_ccli_id' => '111',
    ]);

    ServiceSong::create([
        'service_id' => $service->id,
        'song_id' => null,
        'song_arrangement_id' => null,
        'use_translation' => false,
        'order' => 2,
        'cts_song_name' => 'Unmatched',
        'cts_ccli_id' => '222',
    ]);

    Slide::factory()->create([
        'service_id' => $service->id,
        'type' => 'sermon',
    ]);

    $response = $this->actingAs($this->user)
        ->postJson(route('services.finalize', $service), ['confirmed' => false]);

    $data = $response->json();
    expect($data['needs_confirmation'])->toBeTrue()
        ->and($data['warnings'])->toContain('Nur 1 von 2 Songs sind zugeordnet.')
        ->and($data['warnings'])->toContain('Nur 1 von 2 Songs haben ein Arrangement.');
});

test('finalize warnt bei fehlenden predigtfolien', function () {
    $service = Service::factory()->create(['finalized_at' => null]);

    $song = Song::factory()->create();
    $arrangement = SongArrangement::factory()->create(['song_id' => $song->id]);

    ServiceSong::create([
        'service_id' => $service->id,
        'song_id' => $song->id,
        'song_arrangement_id' => $arrangement->id,
        'use_translation' => false,
        'order' => 1,
        'cts_song_name' => 'Song',
        'cts_ccli_id' => '111',
    ]);

    // No sermon slides

    $response = $this->actingAs($this->user)
        ->postJson(route('services.finalize', $service), ['confirmed' => false]);

    $data = $response->json();
    expect($data['needs_confirmation'])->toBeTrue()
        ->and($data['warnings'])->toContain('Es wurden keine Predigtfolien hochgeladen.');
});

test('reopen setzt finalized_at zurueck', function () {
    $service = Service::factory()->create(['finalized_at' => now()]);

    $response = $this->actingAs($this->user)
        ->post(route('services.reopen', $service));

    $response->assertRedirect(route('services.index'));
    expect($service->fresh()->finalized_at)->toBeNull();
});

test('download nicht-finalisierter service gibt 403 zurueck', function () {
    $service = Service::factory()->create(['finalized_at' => null]);

    $response = $this->actingAs($this->user)
        ->getJson(route('services.download', $service));

    $response->assertForbidden();
});

test('download finalisierter service ohne songs gibt 422 zurueck', function () {
    $service = Service::factory()->create(['finalized_at' => now()]);

    $response = $this->actingAs($this->user)
        ->getJson(route('services.download', $service));

    $response->assertUnprocessable()
        ->assertJson([
            'message' => 'Keine Songs mit Inhalt zum Exportieren gefunden.',
        ]);
});

test('finalize erfordert authentifizierung', function () {
    $service = Service::factory()->create();

    $response = $this->postJson(route('services.finalize', $service));

    $response->assertUnauthorized();
});

test('download erfordert authentifizierung', function () {
    $service = Service::factory()->create();

    $response = $this->getJson(route('services.download', $service));

    $response->assertUnauthorized();
});

test('service model isReadyToFinalize accessor', function () {
    $service = Service::factory()->create(['finalized_at' => null]);

    // No songs, no sermon slides → only sermon warning
    expect($service->is_ready_to_finalize)->toBeFalse();

    Slide::factory()->create([
        'service_id' => $service->id,
        'type' => 'sermon',
    ]);

    // Refresh to clear cached relations
    $service->refresh();

    // No songs, has sermon slides → ready (0/0 songs is not a warning)
    expect($service->is_ready_to_finalize)->toBeTrue();
});

test('finalization status mit service ohne songs warnt nur bei predigtfolien', function () {
    $service = Service::factory()->create(['finalized_at' => null]);

    $status = $service->finalizationStatus();

    // No songs: no song warnings. Only sermon slides warning.
    expect($status['ready'])->toBeFalse()
        ->and($status['warnings'])->toHaveCount(1)
        ->and($status['warnings'][0])->toContain('Predigtfolien');
});

// Agenda-based finalization tests
test('agenda finalization warnt bei unzugeordneten songs', function () {
    $service = Service::factory()->create(['finalized_at' => null]);

    // Create an unmatched song via agenda item
    $serviceSong = ServiceSong::create([
        'service_id' => $service->id,
        'song_id' => null,
        'song_arrangement_id' => null,
        'use_translation' => false,
        'order' => 1,
        'cts_song_name' => 'Unzugeordneter Song',
        'cts_ccli_id' => '12345',
    ]);

    ServiceAgendaItem::create([
        'service_id' => $service->id,
        'position' => '1',
        'title' => 'Song 1',
        'type' => 'Song',
        'service_song_id' => $serviceSong->id,
        'sort_order' => 1,
    ]);

    $status = $service->finalizationStatus();

    expect($status['ready'])->toBeFalse()
        ->and($status['warnings'])->toContain('Unzugeordneter Song wurde noch nicht zugeordnet');
});

test('agenda finalization warnt bei songs ohne arrangement', function () {
    $service = Service::factory()->create(['finalized_at' => null]);
    $song = Song::factory()->create();

    // Song is matched but has no arrangement
    $serviceSong = ServiceSong::create([
        'service_id' => $service->id,
        'song_id' => $song->id,
        'song_arrangement_id' => null,
        'use_translation' => false,
        'order' => 1,
        'cts_song_name' => 'Song ohne Arrangement',
        'cts_ccli_id' => '12345',
    ]);

    ServiceAgendaItem::create([
        'service_id' => $service->id,
        'position' => '1',
        'title' => 'Song 1',
        'type' => 'Song',
        'service_song_id' => $serviceSong->id,
        'sort_order' => 1,
    ]);

    $status = $service->finalizationStatus();

    expect($status['ready'])->toBeFalse()
        ->and($status['warnings'])->toContain('Song ohne Arrangement hat kein Arrangement ausgewählt');
});

test('agenda finalization bereit wenn alle songs zugeordnet und arrangement', function () {
    $service = Service::factory()->create(['finalized_at' => null]);
    $song = Song::factory()->create();
    $arrangement = SongArrangement::factory()->create(['song_id' => $song->id]);

    // Song is matched with arrangement
    $serviceSong = ServiceSong::create([
        'service_id' => $service->id,
        'song_id' => $song->id,
        'song_arrangement_id' => $arrangement->id,
        'use_translation' => false,
        'order' => 1,
        'cts_song_name' => 'Zugeordneter Song',
        'cts_ccli_id' => '12345',
    ]);

    ServiceAgendaItem::create([
        'service_id' => $service->id,
        'position' => '1',
        'title' => 'Song 1',
        'type' => 'Song',
        'service_song_id' => $serviceSong->id,
        'sort_order' => 1,
    ]);

    // Add sermon slides
    Slide::factory()->create([
        'service_id' => $service->id,
        'type' => 'sermon',
    ]);

    $status = $service->finalizationStatus();

    expect($status['ready'])->toBeTrue()
        ->and($status['warnings'])->toHaveCount(0);
});

test('agenda finalization warnt wenn keine predigtfolien und sermon setting konfiguriert', function () {
    $service = Service::factory()->create(['finalized_at' => null]);

    // Configure sermon pattern
    Setting::set('agenda_sermon_matching', 'Predigt*');

    $song = Song::factory()->create();
    $arrangement = SongArrangement::factory()->create(['song_id' => $song->id]);

    $serviceSong = ServiceSong::create([
        'service_id' => $service->id,
        'song_id' => $song->id,
        'song_arrangement_id' => $arrangement->id,
        'use_translation' => false,
        'order' => 1,
        'cts_song_name' => 'Zugeordneter Song',
        'cts_ccli_id' => '12345',
    ]);

    // Create agenda item for sermon (matches pattern)
    ServiceAgendaItem::create([
        'service_id' => $service->id,
        'position' => '1',
        'title' => 'Predigt',
        'type' => 'Default',
        'sort_order' => 1,
    ]);

    ServiceAgendaItem::create([
        'service_id' => $service->id,
        'position' => '2',
        'title' => 'Song 1',
        'type' => 'Song',
        'service_song_id' => $serviceSong->id,
        'sort_order' => 2,
    ]);

    // No sermon slides
    $status = $service->finalizationStatus();

    expect($status['ready'])->toBeFalse()
        ->and($status['warnings'])->toContain('Keine Predigt-Folien hochgeladen');
});

test('agenda finalization ok wenn predigtfolien bei sermon item vorhanden', function () {
    $service = Service::factory()->create(['finalized_at' => null]);

    // Configure sermon pattern
    Setting::set('agenda_sermon_matching', 'Predigt*');

    $song = Song::factory()->create();
    $arrangement = SongArrangement::factory()->create(['song_id' => $song->id]);

    $serviceSong = ServiceSong::create([
        'service_id' => $service->id,
        'song_id' => $song->id,
        'song_arrangement_id' => $arrangement->id,
        'use_translation' => false,
        'order' => 1,
        'cts_song_name' => 'Zugeordneter Song',
        'cts_ccli_id' => '12345',
    ]);

    // Create sermon agenda item
    $sermonItem = ServiceAgendaItem::create([
        'service_id' => $service->id,
        'position' => '1',
        'title' => 'Predigt',
        'type' => 'Default',
        'sort_order' => 1,
    ]);

    ServiceAgendaItem::create([
        'service_id' => $service->id,
        'position' => '2',
        'title' => 'Song 1',
        'type' => 'Song',
        'service_song_id' => $serviceSong->id,
        'sort_order' => 2,
    ]);

    // Add sermon slides to the sermon agenda item
    Slide::factory()->create([
        'service_id' => $service->id,
        'service_agenda_item_id' => $sermonItem->id,
    ]);

    $status = $service->finalizationStatus();

    expect($status['ready'])->toBeTrue()
        ->and($status['warnings'])->toHaveCount(0);
});

test('agenda finalization warnt wenn keine predigtfolien und kein sermon setting', function () {
    $service = Service::factory()->create(['finalized_at' => null]);

    // No sermon pattern setting configured
    Setting::set('agenda_sermon_matching', '');

    $song = Song::factory()->create();
    $arrangement = SongArrangement::factory()->create(['song_id' => $song->id]);

    $serviceSong = ServiceSong::create([
        'service_id' => $service->id,
        'song_id' => $song->id,
        'song_arrangement_id' => $arrangement->id,
        'use_translation' => false,
        'order' => 1,
        'cts_song_name' => 'Zugeordneter Song',
        'cts_ccli_id' => '12345',
    ]);

    ServiceAgendaItem::create([
        'service_id' => $service->id,
        'position' => '1',
        'title' => 'Song 1',
        'type' => 'Song',
        'service_song_id' => $serviceSong->id,
        'sort_order' => 1,
    ]);

    // No sermon slides - fallback should warn
    $status = $service->finalizationStatus();

    expect($status['ready'])->toBeFalse()
        ->and($status['warnings'])->toContain('Keine Predigt-Folien hochgeladen');
});
