<?php

declare(strict_types=1);

namespace Tests\Domain\Manga\Infrastructure\Service;

use App\Domain\Manga\Infrastructure\Service\FilenameAnalyzer;
use PHPUnit\Framework\TestCase;

class FilenameAnalyzerTest extends TestCase
{
    private FilenameAnalyzer $analyzer;

    protected function setUp(): void
    {
        $this->analyzer = new FilenameAnalyzer();
    }

    public function test_it_analyzes_one_piece_filename_correctly(): void
    {
        // Given
        $filename = 'one-piece_vol108_ch1094.cbz';

        // When
        $result = $this->analyzer->analyze($filename);

        // Then
        $this->assertEquals('one-piece', $result->getTitle()->getValue());
        $this->assertEquals(1094.0, $result->getChapterNumber()->getValue());
        $this->assertEquals(108.0, $result->getVolumeNumber()->getValue());
        $this->assertTrue($result->hasChapterNumber());
        $this->assertTrue($result->hasVolumeNumber());
    }

    public function test_it_handles_different_filename_formats(): void
    {
        $testCases = [
            // Format underscore
            [
                'filename' => 'attack-on-titan_vol32_ch130.cbz',
                'expectedTitle' => 'attack-on-titan',
                'expectedChapter' => 130.0,
                'expectedVolume' => 32.0,
            ],
            // Format avec espaces
            [
                'filename' => 'Dragon Ball vol 1 ch 5.cbz',
                'expectedTitle' => 'Dragon Ball',
                'expectedChapter' => 5.0,
                'expectedVolume' => 1.0,
            ],
            // Format avec tirets
            [
                'filename' => 'my-hero-academia-vol15-ch150.cbr',
                'expectedTitle' => 'my-hero-academia',
                'expectedChapter' => 150.0,
                'expectedVolume' => 15.0,
            ],
            // Format chapitre décimal
            [
                'filename' => 'naruto_vol50_ch456.5.cbz',
                'expectedTitle' => 'naruto',
                'expectedChapter' => 456.5,
                'expectedVolume' => 50.0,
            ],
        ];

        foreach ($testCases as $case) {
            $result = $this->analyzer->analyze($case['filename']);

            $this->assertEquals($case['expectedTitle'], $result->getTitle()->getValue(),
                "Failed for filename: {$case['filename']}");
            $this->assertEquals($case['expectedChapter'], $result->getChapterNumber()->getValue(),
                "Failed chapter extraction for: {$case['filename']}");
            $this->assertEquals($case['expectedVolume'], $result->getVolumeNumber()->getValue(),
                "Failed volume extraction for: {$case['filename']}");
        }
    }

    public function test_it_extracts_and_cleans_title(): void
    {
        // Given
        $filename = 'one-piece_vol108_ch1094.cbz';

        // When
        $result = $this->analyzer->analyze($filename);

        // Then - should extract and clean the title
        $this->assertEquals('one-piece', $result->getTitle()->getValue());
        $this->assertNotEmpty($result->getTitle()->getValue(), 'Title should not be empty');
    }

    public function test_it_handles_files_without_volume_or_chapter(): void
    {
        $testCases = [
            [
                'filename' => 'one-piece.cbz',
                'expectedTitle' => 'one-piece',
            ],
            [
                'filename' => 'manga_title_only.cbr',
                'expectedTitle' => 'manga_title_only',
            ],
        ];

        foreach ($testCases as $case) {
            $result = $this->analyzer->analyze($case['filename']);

            $this->assertEquals($case['expectedTitle'], $result->getTitle()->getValue());
            $this->assertFalse($result->hasChapterNumber());
            $this->assertFalse($result->hasVolumeNumber());
            $this->assertNull($result->getChapterNumber());
            $this->assertNull($result->getVolumeNumber());
        }
    }

    public function test_it_handles_cbz_and_cbr_extensions(): void
    {
        // Given
        $testCases = [
            ['filename' => 'one-piece.cbz', 'expectedTitle' => 'one-piece'],
            ['filename' => 'manga.cbr', 'expectedTitle' => 'manga'],
            ['filename' => 'test.CBZ', 'expectedTitle' => 'test'],
            ['filename' => 'test.CBR', 'expectedTitle' => 'test'],
        ];

        foreach ($testCases as $case) {
            // When
            $result = $this->analyzer->analyze($case['filename']);

            // Then - L'extension est enlevée et le titre est extrait
            $this->assertEquals($case['expectedTitle'], $result->getTitle()->getValue());
        }
    }

    public function test_it_cleans_common_patterns(): void
    {
        $testCases = [
            [
                'filename' => 'one-piece-scan-fr_vol108_ch1094.cbz',
                'cleanedTitle' => 'one-piece',
            ],
            [
                'filename' => 'manga-raw-jp_vol1_ch1.cbz',
                'cleanedTitle' => 'manga',
            ],
        ];

        foreach ($testCases as $case) {
            $result = $this->analyzer->analyze($case['filename']);
            $title = $result->getTitle()->getValue();

            // Vérifie que le titre est nettoyé
            $this->assertEquals($case['cleanedTitle'], $title,
                "Title should be cleaned for {$case['filename']}");

            // Vérifie que le titre nettoyé ne contient pas les mots indésirables
            $this->assertDoesNotMatchRegularExpression('/\b(?:scan|raw|fr|en|jp|hq|lq)\b/i', $title,
                "Cleaned title should not contain unwanted patterns for {$case['filename']}");
        }
    }

    public function test_it_handles_filename_with_only_volume(): void
    {
        $testCases = [
            [
                'filename' => 'one-piece_vol108.cbz',
                'expectedTitle' => 'one-piece',
                'expectedVolume' => 108.0,
            ],
            [
                'filename' => 'attack-on-titan vol 32.cbz',
                'expectedTitle' => 'attack-on-titan',
                'expectedVolume' => 32.0,
            ],
            [
                'filename' => 'naruto-tome-50.cbz',
                'expectedTitle' => 'naruto',
                'expectedVolume' => 50.0,
            ],
            [
                'filename' => 'bleach_t15.cbz',
                'expectedTitle' => 'bleach',
                'expectedVolume' => 15.0,
            ],
        ];

        foreach ($testCases as $case) {
            $result = $this->analyzer->analyze($case['filename']);

            $this->assertEquals($case['expectedTitle'], $result->getTitle()->getValue(),
                "Failed title extraction for: {$case['filename']}");
            $this->assertEquals($case['expectedVolume'], $result->getVolumeNumber()->getValue(),
                "Failed volume extraction for: {$case['filename']}");
            $this->assertFalse($result->hasChapterNumber(),
                "Should not have chapter for: {$case['filename']}");
        }
    }

    public function test_it_handles_filename_with_only_chapter(): void
    {
        $testCases = [
            [
                'filename' => 'naruto_ch456.cbz',
                'expectedTitle' => 'naruto',
                'expectedChapter' => 456.0,
            ],
            [
                'filename' => 'my-hero-academia ch 150.cbz',
                'expectedTitle' => 'my-hero-academia',
                'expectedChapter' => 150.0,
            ],
            [
                'filename' => 'bleach-chap-200.cbz',
                'expectedTitle' => 'bleach',
                'expectedChapter' => 200.0,
            ],
            [
                'filename' => 'one-piece_chapter_1094.cbz',
                'expectedTitle' => 'one-piece',
                'expectedChapter' => 1094.0,
            ],
        ];

        foreach ($testCases as $case) {
            $result = $this->analyzer->analyze($case['filename']);

            $this->assertEquals($case['expectedTitle'], $result->getTitle()->getValue(),
                "Failed title extraction for: {$case['filename']}");
            $this->assertEquals($case['expectedChapter'], $result->getChapterNumber()->getValue(),
                "Failed chapter extraction for: {$case['filename']}");
            $this->assertFalse($result->hasVolumeNumber(),
                "Should not have volume for: {$case['filename']}");
        }
    }

    public function test_it_handles_full_dash_patterns(): void
    {
        $testCases = [
            [
                'filename' => 'berserk-volume-42.cbz',
                'expectedTitle' => 'berserk',
                'expectedVolume' => 42.0,
            ],
            [
                'filename' => 'berserk-chapter-100.cbz',
                'expectedTitle' => 'berserk',
                'expectedChapter' => 100.0,
            ],
            [
                'filename' => 'berserk-chapitre-100.cbz',
                'expectedTitle' => 'berserk',
                'expectedChapter' => 100.0,
            ],
            [
                'filename' => 'berserk-volume-42-chapter-100.cbz',
                'expectedTitle' => 'berserk',
                'expectedVolume' => 42.0,
                'expectedChapter' => 100.0,
            ],
            [
                'filename' => 'berserk-chapitre-100-volume-42.cbz',
                'expectedTitle' => 'berserk',
                'expectedVolume' => 42.0,
                'expectedChapter' => 100.0,
            ],
        ];

        foreach ($testCases as $case) {
            $result = $this->analyzer->analyze($case['filename']);

            $this->assertEquals($case['expectedTitle'], $result->getTitle()->getValue(),
                "Failed title extraction for: {$case['filename']}");

            if (isset($case['expectedVolume'])) {
                $this->assertTrue($result->hasVolumeNumber(),
                    "Should have volume for: {$case['filename']}");
                $this->assertEquals($case['expectedVolume'], $result->getVolumeNumber()->getValue(),
                    "Failed volume extraction for: {$case['filename']}");
            } else {
                $this->assertFalse($result->hasVolumeNumber(),
                    "Should not have volume for: {$case['filename']}");
            }

            if (isset($case['expectedChapter'])) {
                $this->assertTrue($result->hasChapterNumber(),
                    "Should have chapter for: {$case['filename']}");
                $this->assertEquals($case['expectedChapter'], $result->getChapterNumber()->getValue(),
                    "Failed chapter extraction for: {$case['filename']}");
            } else {
                $this->assertFalse($result->hasChapterNumber(),
                    "Should not have chapter for: {$case['filename']}");
            }
        }
    }
}
