<?php

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 App\Services\TranslationService;
use Illuminate\Support\Facades\Http;

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

test('fetchFromUrl returns text from successful HTTP response', function () {
    Http::fake([
        'https://example.com/lyrics' => Http::response('<html><body><p>Zeile 1</p><p>Zeile 2</p></body></html>', 200),
    ]);

    $result = $this->service->fetchFromUrl('https://example.com/lyrics');

    expect($result)->not->toBeNull();
    expect($result)->toContain('Zeile 1');
    expect($result)->toContain('Zeile 2');
    expect($result)->not->toContain('<p>');
    expect($result)->not->toContain('<html>');
});

test('fetchFromUrl returns null on HTTP failure', function () {
    Http::fake([
        'https://example.com/broken' => Http::response('Not Found', 404),
    ]);

    $result = $this->service->fetchFromUrl('https://example.com/broken');

    expect($result)->toBeNull();
});

test('fetchFromUrl returns null on connection error', function () {
    Http::fake([
        'https://timeout.example.com/*' => fn () => throw new \Illuminate\Http\Client\ConnectionException('Timeout'),
    ]);

    $result = $this->service->fetchFromUrl('https://timeout.example.com/lyrics');

    expect($result)->toBeNull();
});

test('fetchFromUrl returns null for empty response body', function () {
    Http::fake([
        'https://example.com/empty' => Http::response('', 200),
    ]);

    $result = $this->service->fetchFromUrl('https://example.com/empty');

    expect($result)->toBeNull();
});

function makeSongWithDefaultArrangement(): array
{
    $song = Song::factory()->create(['has_translation' => false]);
    $arrangement = SongArrangement::factory()->create([
        'song_id' => $song->id,
        'name' => 'Normal',
        'is_default' => true,
    ]);

    return [$song, $arrangement];
}

function attachLabelWithSlides(SongArrangement $arrangement, string $labelName, array $slides, int $arrangementOrder): SongSection
{
    $label = Label::firstOrCreate(['name' => $labelName]);
    $section = SongSection::firstOrCreate(
        ['song_id' => $arrangement->song_id, 'label_id' => $label->id],
        ['order' => $arrangementOrder],
    );
    SongArrangementLabel::factory()->create([
        'song_arrangement_id' => $arrangement->id,
        'song_section_id' => $section->id,
        'order' => $arrangementOrder,
    ]);

    foreach ($slides as $slide) {
        $section->slides()->create($slide);
    }

    return $section;
}

test('importTranslation distributes lines by slide line counts', function () {
    [$song, $arrangement] = makeSongWithDefaultArrangement();

    $label = attachLabelWithSlides($arrangement, 'Strophe 1 - dist', [], 1);

    $slide1 = SongSlide::factory()->create([
        'song_section_id' => $label->id,
        'order' => 1,
        'text_content' => "Original 1\nOriginal 2\nOriginal 3\nOriginal 4",
    ]);

    $slide2 = SongSlide::factory()->create([
        'song_section_id' => $label->id,
        'order' => 2,
        'text_content' => "Original 5\nOriginal 6",
    ]);

    $slide3 = SongSlide::factory()->create([
        'song_section_id' => $label->id,
        'order' => 3,
        'text_content' => "Original 7\nOriginal 8\nOriginal 9\nOriginal 10",
    ]);

    $translatedText = "Zeile 1\nZeile 2\nZeile 3\nZeile 4\nZeile 5\nZeile 6\nZeile 7\nZeile 8\nZeile 9\nZeile 10";

    $this->service->importTranslation($song, $translatedText);

    $slide1->refresh();
    $slide2->refresh();
    $slide3->refresh();

    expect($slide1->text_content_translated)->toBe("Zeile 1\nZeile 2\nZeile 3\nZeile 4");
    expect($slide2->text_content_translated)->toBe("Zeile 5\nZeile 6");
    expect($slide3->text_content_translated)->toBe("Zeile 7\nZeile 8\nZeile 9\nZeile 10");
});

test('importTranslation distributes across multiple groups', function () {
    [$song, $arrangement] = makeSongWithDefaultArrangement();

    $label1 = attachLabelWithSlides($arrangement, 'Strophe 1 - multi', [], 1);
    $label2 = attachLabelWithSlides($arrangement, 'Refrain - multi', [], 2);

    $slide1 = SongSlide::factory()->create([
        'song_section_id' => $label1->id,
        'order' => 1,
        'text_content' => "Line A\nLine B",
    ]);

    $slide2 = SongSlide::factory()->create([
        'song_section_id' => $label2->id,
        'order' => 1,
        'text_content' => "Line C\nLine D\nLine E",
    ]);

    $translatedText = "Über A\nÜber B\nÜber C\nÜber D\nÜber E";

    $this->service->importTranslation($song, $translatedText);

    $slide1->refresh();
    $slide2->refresh();

    expect($slide1->text_content_translated)->toBe("Über A\nÜber B");
    expect($slide2->text_content_translated)->toBe("Über C\nÜber D\nÜber E");
});

test('importTranslation handles fewer translation lines than original', function () {
    [$song, $arrangement] = makeSongWithDefaultArrangement();

    $label = attachLabelWithSlides($arrangement, 'Strophe 1 - fewer', [], 1);

    $slide1 = SongSlide::factory()->create([
        'song_section_id' => $label->id,
        'order' => 1,
        'text_content' => "Line 1\nLine 2\nLine 3",
    ]);

    $slide2 = SongSlide::factory()->create([
        'song_section_id' => $label->id,
        'order' => 2,
        'text_content' => "Line 4\nLine 5",
    ]);

    $translatedText = "Zeile 1\nZeile 2\nZeile 3";

    $this->service->importTranslation($song, $translatedText);

    $slide1->refresh();
    $slide2->refresh();

    expect($slide1->text_content_translated)->toBe("Zeile 1\nZeile 2\nZeile 3");
    expect($slide2->text_content_translated)->toBe('');
});

test('importTranslation marks song as translated', function () {
    [$song, $arrangement] = makeSongWithDefaultArrangement();

    $label = attachLabelWithSlides($arrangement, 'Strophe 1 - mark', [], 1);
    SongSlide::factory()->create([
        'song_section_id' => $label->id,
        'order' => 1,
        'text_content' => 'Line 1',
    ]);

    $this->service->importTranslation($song, 'Zeile 1');

    $song->refresh();
    expect($song->has_translation)->toBeTrue();
});

test('markAsTranslated sets has_translation to true', function () {
    $song = Song::factory()->create(['has_translation' => false]);

    $this->service->markAsTranslated($song);

    $song->refresh();
    expect($song->has_translation)->toBeTrue();
});

test('removeTranslation clears all translated text and sets flag to false', function () {
    [$song, $arrangement] = makeSongWithDefaultArrangement();
    $song->update(['has_translation' => true]);

    $label = attachLabelWithSlides($arrangement, 'Strophe 1 - remove', [], 1);

    $slide1 = SongSlide::factory()->create([
        'song_section_id' => $label->id,
        'order' => 1,
        'text_content' => 'Original',
        'text_content_translated' => 'Übersetzt',
    ]);

    $slide2 = SongSlide::factory()->create([
        'song_section_id' => $label->id,
        'order' => 2,
        'text_content' => 'Original 2',
        'text_content_translated' => 'Übersetzt 2',
    ]);

    $this->service->removeTranslation($song);

    $song->refresh();
    $slide1->refresh();
    $slide2->refresh();

    expect($song->has_translation)->toBeFalse();
    expect($slide1->text_content_translated)->toBeNull();
    expect($slide2->text_content_translated)->toBeNull();
});

test('POST translation/fetch-url returns scraped text', function () {
    Http::fake([
        'https://lyrics.example.com/song' => Http::response('<div>Liedtext Zeile 1</div>', 200),
    ]);

    $response = $this->actingAs($this->user)
        ->postJson('/api/translation/fetch-url', [
            'url' => 'https://lyrics.example.com/song',
        ]);

    $response->assertOk()
        ->assertJsonStructure(['text']);

    expect($response->json('text'))->toContain('Liedtext Zeile 1');
});

test('POST translation/fetch-url returns error on failure', function () {
    Http::fake([
        'https://broken.example.com/*' => Http::response('', 500),
    ]);

    $response = $this->actingAs($this->user)
        ->postJson('/api/translation/fetch-url', [
            'url' => 'https://broken.example.com/song',
        ]);

    $response->assertStatus(422)
        ->assertJsonFragment(['message' => 'Konnte Text nicht abrufen']);
});

test('POST translation/fetch-url validates url field', function () {
    $response = $this->actingAs($this->user)
        ->postJson('/api/translation/fetch-url', []);

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

test('POST songs/{song}/translation/import distributes and saves translation', function () {
    [$song, $arrangement] = makeSongWithDefaultArrangement();

    $label = attachLabelWithSlides($arrangement, 'Strophe 1 - controller', [], 1);

    $slide = SongSlide::factory()->create([
        'song_section_id' => $label->id,
        'order' => 1,
        'text_content' => "Line 1\nLine 2",
    ]);

    $response = $this->actingAs($this->user)
        ->postJson("/api/songs/{$song->id}/translation/import", [
            'text' => "Zeile 1\nZeile 2",
        ]);

    $response->assertOk()
        ->assertJsonFragment(['message' => 'Übersetzung erfolgreich importiert']);

    $slide->refresh();
    $song->refresh();

    expect($slide->text_content_translated)->toBe("Zeile 1\nZeile 2");
    expect($song->has_translation)->toBeTrue();
});

test('POST songs/{song}/translation/import validates text field', function () {
    $song = Song::factory()->create();

    $response = $this->actingAs($this->user)
        ->postJson("/api/songs/{$song->id}/translation/import", []);

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

test('POST songs/{song}/translation/import returns 404 for missing song', function () {
    $response = $this->actingAs($this->user)
        ->postJson('/api/songs/99999/translation/import', [
            'text' => 'Some text',
        ]);

    $response->assertNotFound();
});

test('DELETE songs/{song}/translation removes translation', function () {
    [$song, $arrangement] = makeSongWithDefaultArrangement();
    $song->update(['has_translation' => true]);

    $label = attachLabelWithSlides($arrangement, 'Strophe 1 - delete', [], 1);

    SongSlide::factory()->create([
        'song_section_id' => $label->id,
        'order' => 1,
        'text_content' => 'Original',
        'text_content_translated' => 'Übersetzt',
    ]);

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

    $response->assertOk()
        ->assertJsonFragment(['message' => 'Übersetzung entfernt']);

    $song->refresh();
    expect($song->has_translation)->toBeFalse();
});

test('translation endpoints require authentication', function () {
    $this->postJson('/api/translation/fetch-url', ['url' => 'https://example.com'])
        ->assertUnauthorized();

    $this->postJson('/api/songs/1/translation/import', ['text' => 'test'])
        ->assertUnauthorized();

    $this->deleteJson('/api/songs/1/translation')
        ->assertUnauthorized();
});
