<?php

namespace Tests\Feature;

use App\Models\Label;
use App\Models\Song;
use App\Models\SongArrangement;
use App\Models\SongArrangementLabel;
use App\Models\SongSection;
use App\Models\SongSlide;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class SongSectionControllerTest extends TestCase
{
    use RefreshDatabase;

    public function test_patch_edits_only_target_song_section(): void
    {
        $this->actingAs(User::factory()->create());
        $label = Label::factory()->create(['name' => 'Chorus']);
        [$songA, $sectionA] = $this->createSongWithSection($label, ['Alter Refrain']);
        [, $sectionB] = $this->createSongWithSection($label, ['Anderer Refrain']);

        $response = $this->patchJson(route('songs.sections.update', [$songA, $sectionA]), [
            'slides' => [
                ['text_content' => 'Neuer Refrain', 'text_content_translated' => 'New chorus'],
                ['text_content' => 'Zweiter Block', 'text_content_translated' => null],
            ],
        ]);

        $response->assertOk()
            ->assertJsonPath('data.has_translation', true)
            ->assertJsonPath('data.groups.0.slides.0.text_content', 'Neuer Refrain');

        $this->assertSame(['Neuer Refrain', 'Zweiter Block'], $sectionA->slides()->orderBy('order')->pluck('text_content')->all());
        $this->assertSame(['Anderer Refrain'], $sectionB->slides()->orderBy('order')->pluck('text_content')->all());
        $this->assertTrue($songA->fresh()->has_translation);
    }

    public function test_post_adds_section_reuses_normalized_label_and_appends_default_arrangement(): void
    {
        $this->actingAs(User::factory()->create());
        $song = Song::factory()->create(['has_translation' => false]);
        $arrangement = SongArrangement::factory()->create([
            'song_id' => $song->id,
            'name' => 'Normal',
            'is_default' => true,
        ]);
        $existingLabel = Label::factory()->create(['name' => 'Verse 3', 'color' => '#111111']);

        $response = $this->postJson(route('songs.sections.store', $song), [
            'label_name' => 'Strophe 3',
            'color' => '#ABCDEF',
            'slides' => [
                ['text_content' => 'Neue Strophe', 'text_content_translated' => null],
            ],
        ]);

        $response->assertCreated()
            ->assertJsonPath('data.groups.0.name', 'Verse 3')
            ->assertJsonPath('data.groups.0.slides.0.text_content', 'Neue Strophe');

        $this->assertSame(1, Label::query()->where('name', 'Verse 3')->count());
        $section = SongSection::query()->where('song_id', $song->id)->where('label_id', $existingLabel->id)->first();

        $this->assertNotNull($section);
        $this->assertDatabaseHas('song_slides', [
            'song_section_id' => $section->id,
            'text_content' => 'Neue Strophe',
        ]);
        $this->assertDatabaseHas('song_arrangement_labels', [
            'song_arrangement_id' => $arrangement->id,
            'song_section_id' => $section->id,
            'order' => 1,
        ]);
    }

    public function test_delete_removes_section_slides_and_junction_for_this_song_only_but_keeps_global_label(): void
    {
        $this->actingAs(User::factory()->create());
        $label = Label::factory()->create(['name' => 'Bridge']);
        [$songA, $sectionA, $arrangementA] = $this->createSongWithSection($label, ['Bridge A']);
        [, $sectionB] = $this->createSongWithSection($label, ['Bridge B']);
        $slideId = $sectionA->slides()->first()->id;
        $junctionId = SongArrangementLabel::query()
            ->where('song_arrangement_id', $arrangementA->id)
            ->where('song_section_id', $sectionA->id)
            ->value('id');

        $response = $this->deleteJson(route('songs.sections.destroy', [$songA, $sectionA]));

        $response->assertOk()
            ->assertJsonPath('data.groups', []);

        $this->assertDatabaseMissing('song_sections', ['id' => $sectionA->id]);
        $this->assertDatabaseMissing('song_slides', ['id' => $slideId]);
        $this->assertDatabaseMissing('song_arrangement_labels', ['id' => $junctionId]);
        $this->assertDatabaseHas('labels', ['id' => $label->id]);
        $this->assertDatabaseHas('song_sections', ['id' => $sectionB->id]);
        $this->assertSame(['Bridge B'], $sectionB->slides()->pluck('text_content')->all());
    }

    public function test_validation_and_ownership_errors_are_german(): void
    {
        $this->actingAs(User::factory()->create());
        $label = Label::factory()->create(['name' => 'Verse 1']);
        [$songA, $sectionA] = $this->createSongWithSection($label, ['Song A']);
        [$songB] = $this->createSongWithSection(Label::factory()->create(['name' => 'Chorus']), ['Song B']);

        $this->patchJson(route('songs.sections.update', [$songB, $sectionA]), [
            'slides' => [
                ['text_content' => 'Falsch'],
            ],
        ])->assertNotFound()
            ->assertJsonPath('message', 'Sektion nicht gefunden.');

        $this->postJson(route('songs.sections.store', $songA), [
            'slides' => [
                ['text_content' => 'Ohne Label'],
            ],
        ])->assertUnprocessable()
            ->assertJsonPath('message', 'Bitte gib einen Namen für die Sektion ein.');

        $this->postJson(route('songs.sections.store', $songA), [
            'label_name' => 'Verse 1',
            'slides' => [
                ['text_content' => 'Doppelt'],
            ],
        ])->assertUnprocessable()
            ->assertJsonPath('message', 'Dieser Abschnitt existiert bereits in diesem Lied.');
    }

    public function test_has_translation_is_recomputed_after_edits(): void
    {
        $this->actingAs(User::factory()->create());
        [$song, $section] = $this->createSongWithSection(Label::factory()->create(['name' => 'Verse 1']), ['Original']);

        $this->patchJson(route('songs.sections.update', [$song, $section]), [
            'slides' => [
                ['text_content' => 'Original', 'text_content_translated' => 'Übersetzt'],
            ],
        ])->assertOk()
            ->assertJsonPath('data.has_translation', true);

        $this->assertTrue($song->fresh()->has_translation);

        $this->patchJson(route('songs.sections.update', [$song, $section]), [
            'slides' => [
                ['text_content' => 'Original', 'text_content_translated' => ''],
            ],
        ])->assertOk()
            ->assertJsonPath('data.has_translation', false);

        $this->assertFalse($song->fresh()->has_translation);
    }

    private function createSongWithSection(Label $label, array $slides): array
    {
        $song = Song::factory()->create(['has_translation' => false]);
        $section = SongSection::factory()->create([
            'song_id' => $song->id,
            'label_id' => $label->id,
            'order' => 1,
        ]);

        foreach ($slides as $index => $text) {
            SongSlide::factory()->create([
                'song_section_id' => $section->id,
                'order' => $index + 1,
                'text_content' => $text,
                'text_content_translated' => null,
            ]);
        }

        $arrangement = SongArrangement::factory()->create([
            'song_id' => $song->id,
            'name' => 'Normal',
            'is_default' => true,
        ]);

        SongArrangementLabel::factory()->create([
            'song_arrangement_id' => $arrangement->id,
            'song_section_id' => $section->id,
            'order' => 1,
        ]);

        return [$song, $section, $arrangement];
    }
}
