<?php

use App\Models\Label;
use App\Models\Service;
use App\Models\ServiceSong;
use App\Models\Song;
use App\Models\SongArrangement;
use App\Models\SongArrangementLabel;
use App\Models\User;

beforeEach(function () {
    $this->user = User::factory()->create();
});

test('songs index returns paginated list', function () {
    Song::factory()->count(3)->create();

    $response = $this->actingAs($this->user)
        ->getJson('/api/songs');

    $response->assertOk()
        ->assertJsonStructure([
            'data' => [['id', 'title', 'ccli_id', 'author', 'has_translation']],
            'meta' => ['current_page', 'last_page', 'per_page', 'total'],
        ]);
    expect($response->json('meta.total'))->toBe(3);
});

test('songs index excludes soft-deleted songs', function () {
    Song::factory()->count(2)->create();
    Song::factory()->create(['deleted_at' => now()]);

    $response = $this->actingAs($this->user)
        ->getJson('/api/songs');

    $response->assertOk();
    expect($response->json('meta.total'))->toBe(2);
});

test('songs index search by title', function () {
    Song::factory()->create(['title' => 'Amazing Grace']);
    Song::factory()->create(['title' => 'Holy Spirit']);

    $response = $this->actingAs($this->user)
        ->getJson('/api/songs?search=Amazing');

    $response->assertOk();
    expect($response->json('meta.total'))->toBe(1);
    expect($response->json('data.0.title'))->toBe('Amazing Grace');
});

test('songs index search by ccli id', function () {
    Song::factory()->create(['ccli_id' => '123456', 'title' => 'Song A']);
    Song::factory()->create(['ccli_id' => '789012', 'title' => 'Song B']);

    $response = $this->actingAs($this->user)
        ->getJson('/api/songs?search=123456');

    $response->assertOk();
    expect($response->json('meta.total'))->toBe(1);
    expect($response->json('data.0.ccli_id'))->toBe('123456');
});

test('songs index requires authentication', function () {
    $response = $this->getJson('/api/songs');

    $response->assertUnauthorized();
});

test('store creates song with default groups and arrangement', function () {
    $response = $this->actingAs($this->user)
        ->postJson('/api/songs', [
            'title' => 'Neues Lied',
            'ccli_id' => '999999',
            'author' => 'Test Author',
        ]);

    $response->assertCreated()
        ->assertJsonFragment(['message' => 'Song erfolgreich erstellt']);

    $song = Song::where('title', 'Neues Lied')->first();
    expect($song)->not->toBeNull();

    $arrangement = $song->arrangements()->where('is_default', true)->first();
    expect($arrangement)->not->toBeNull();
    expect($arrangement->name)->toBe('Normal');
    expect($arrangement->arrangementLabels)->toHaveCount(3);
    expect($arrangement->arrangementLabels->sortBy('order')->pluck('label.name')->toArray())
        ->toBe(['Strophe 1', 'Refrain', 'Bridge']);
});

test('store validates required title', function () {
    $response = $this->actingAs($this->user)
        ->postJson('/api/songs', [
            'ccli_id' => '111111',
        ]);

    $response->assertUnprocessable()
        ->assertJsonValidationErrors(['title']);
});

test('store validates unique ccli_id', function () {
    Song::factory()->create(['ccli_id' => '555555']);

    $response = $this->actingAs($this->user)
        ->postJson('/api/songs', [
            'title' => 'Duplicate Song',
            'ccli_id' => '555555',
        ]);

    $response->assertUnprocessable()
        ->assertJsonValidationErrors(['ccli_id']);
});

test('store allows null ccli_id', function () {
    $response = $this->actingAs($this->user)
        ->postJson('/api/songs', [
            'title' => 'Song ohne CCLI',
        ]);

    $response->assertCreated();
    expect(Song::where('title', 'Song ohne CCLI')->first()->ccli_id)->toBeNull();
});

test('show returns song with groups slides and arrangements', function () {
    $song = Song::factory()->create();
    $label = Label::factory()->create(['name' => 'Strophe 1']);
    $arrangement = SongArrangement::factory()->create(['song_id' => $song->id, 'name' => 'Normal', 'is_default' => true]);
    SongArrangementLabel::factory()->create([
        'song_arrangement_id' => $arrangement->id,
        'label_id' => $label->id,
        'order' => 1,
    ]);

    $response = $this->actingAs($this->user)
        ->getJson("/api/songs/{$song->id}");

    $response->assertOk()
        ->assertJsonStructure([
            'data' => [
                'id', 'title', 'ccli_id', 'author', 'copyright_text',
                'has_translation', 'last_used_in_service',
                'groups' => [['id', 'name', 'color', 'order', 'slides']],
                'arrangements' => [['id', 'name', 'is_default', 'arrangement_groups']],
            ],
        ]);
});

test('show returns 404 for nonexistent song', function () {
    $response = $this->actingAs($this->user)
        ->getJson('/api/songs/99999');

    $response->assertNotFound()
        ->assertJsonFragment(['message' => 'Song nicht gefunden']);
});

test('show returns 404 for soft-deleted song', function () {
    $song = Song::factory()->create(['deleted_at' => now()]);

    $response = $this->actingAs($this->user)
        ->getJson("/api/songs/{$song->id}");

    $response->assertNotFound();
});

test('update modifies song metadata', function () {
    $song = Song::factory()->create(['title' => 'Old Title']);

    $response = $this->actingAs($this->user)
        ->putJson("/api/songs/{$song->id}", [
            'title' => 'New Title',
            'author' => 'New Author',
        ]);

    $response->assertOk()
        ->assertJsonFragment(['message' => 'Song erfolgreich aktualisiert']);

    $song->refresh();
    expect($song->title)->toBe('New Title');
    expect($song->author)->toBe('New Author');
});

test('update validates unique ccli_id excluding self', function () {
    $songA = Song::factory()->create(['ccli_id' => '111111']);
    $songB = Song::factory()->create(['ccli_id' => '222222']);

    $response = $this->actingAs($this->user)
        ->putJson("/api/songs/{$songB->id}", [
            'title' => $songB->title,
            'ccli_id' => '111111',
        ]);

    $response->assertUnprocessable()
        ->assertJsonValidationErrors(['ccli_id']);
});

test('update allows keeping own ccli_id', function () {
    $song = Song::factory()->create(['ccli_id' => '333333']);

    $response = $this->actingAs($this->user)
        ->putJson("/api/songs/{$song->id}", [
            'title' => 'Updated Title',
            'ccli_id' => '333333',
        ]);

    $response->assertOk();
});

test('destroy soft-deletes a song', function () {
    $song = Song::factory()->create();

    $response = $this->actingAs($this->user)
        ->deleteJson("/api/songs/{$song->id}");

    $response->assertOk()
        ->assertJsonFragment(['message' => 'Song erfolgreich gelöscht']);

    expect(Song::find($song->id))->toBeNull();
    expect(Song::withTrashed()->find($song->id))->not->toBeNull();
});

test('destroy returns 404 for nonexistent song', function () {
    $response = $this->actingAs($this->user)
        ->deleteJson('/api/songs/99999');

    $response->assertNotFound();
});

test('last_used_in_service returns correct date from service_songs', function () {
    $song = Song::factory()->create();
    $serviceOld = Service::factory()->create(['date' => '2025-06-01']);
    $serviceNew = Service::factory()->create(['date' => '2026-01-15']);

    ServiceSong::factory()->create([
        'song_id' => $song->id,
        'service_id' => $serviceOld->id,
    ]);
    ServiceSong::factory()->create([
        'song_id' => $song->id,
        'service_id' => $serviceNew->id,
    ]);

    $response = $this->actingAs($this->user)
        ->getJson("/api/songs/{$song->id}");

    $response->assertOk();
    expect($response->json('data.last_used_in_service'))->toBe('2026-01-15');
});

test('last_used_in_service returns null when never used', function () {
    $song = Song::factory()->create();

    $response = $this->actingAs($this->user)
        ->getJson("/api/songs/{$song->id}");

    $response->assertOk();
    expect($response->json('data.last_used_in_service'))->toBeNull();
});

test('duplicate arrangement clones arrangement with groups', function () {
    $song = Song::factory()->create();
    $label1 = Label::factory()->create();
    $label2 = Label::factory()->create();

    $arrangement = SongArrangement::factory()->create([
        'song_id' => $song->id,
        'name' => 'Original',
        'is_default' => true,
    ]);
    SongArrangementLabel::factory()->create([
        'song_arrangement_id' => $arrangement->id,
        'label_id' => $label1->id,
        'order' => 1,
    ]);
    SongArrangementLabel::factory()->create([
        'song_arrangement_id' => $arrangement->id,
        'label_id' => $label2->id,
        'order' => 2,
    ]);

    $service = app(\App\Services\SongService::class);
    $clone = $service->duplicateArrangement($arrangement, 'Klone');

    expect($clone->name)->toBe('Klone');
    expect($clone->is_default)->toBeFalse();
    expect($clone->arrangementLabels)->toHaveCount(2);
    expect($clone->arrangementLabels->pluck('label_id')->toArray())
        ->toBe($arrangement->arrangementLabels->pluck('label_id')->toArray());
});
