<?php

namespace App\Tests\Domain\Manga\Application\CommandHandler;

use App\Domain\Manga\Application\Command\ImportChapter;
use App\Domain\Manga\Application\CommandHandler\ImportChapterHandler;
use App\Domain\Manga\Domain\Exception\MangaNotFoundException;
use App\Domain\Manga\Domain\Exception\ChapterNotFoundException;
use App\Domain\Manga\Domain\Model\Chapter;
use App\Domain\Manga\Domain\Model\Manga;
use App\Domain\Manga\Domain\Model\ValueObject\ChapterId;
use App\Domain\Manga\Domain\Model\ValueObject\MangaId;
use App\Domain\Manga\Domain\Model\ValueObject\MangaSlug;
use App\Domain\Manga\Domain\Model\ValueObject\MangaTitle;
use App\Tests\Domain\Manga\Adapter\InMemoryMangaRepository;
use App\Tests\Domain\Scraping\Adapter\InMemoryImageStorage;
use PHPUnit\Framework\TestCase;

class ImportChapterHandlerTest extends TestCase
{
    private InMemoryMangaRepository $mangaRepository;
    private InMemoryImageStorage $imageStorage;
    private ImportChapterHandler $handler;

    protected function setUp(): void
    {
        $this->mangaRepository = new InMemoryMangaRepository();
        $this->imageStorage = new InMemoryImageStorage();
        $this->handler = new ImportChapterHandler(
            $this->mangaRepository,
            $this->imageStorage
        );
    }

    public function test_it_throws_exception_when_chapter_not_found(): void
    {
        // Arrange
        $mangaId = 'manga-123';
        $manga = new Manga(
            new MangaId($mangaId),
            new MangaTitle('One Piece'),
            new MangaSlug('one-piece'),
            'Description',
            'Eiichiro Oda',
            1997,
            ['action', 'adventure'],
            'ongoing'
        );
        $this->mangaRepository->save($manga);

        $cbzBinary = $this->createValidCbzBinary();
        $command = new ImportChapter(
            mangaId: $mangaId,
            chapterNumber: 1.5,
            fileBinary: $cbzBinary
        );

        // Assert
        $this->expectException(ChapterNotFoundException::class);

        // Act
        $this->handler->handle($command);
    }

    public function test_it_updates_existing_chapter_with_new_path(): void
    {
        // Arrange
        $mangaId = 'manga-123';
        $manga = new Manga(
            new MangaId($mangaId),
            new MangaTitle('One Piece'),
            new MangaSlug('one-piece'),
            'Description',
            'Eiichiro Oda',
            1997,
            ['action', 'adventure'],
            'ongoing'
        );
        // Create an existing chapter without pages and add through the aggregate
        $existingChapter = new Chapter(
            new ChapterId('chapter-123'),
            new MangaId($mangaId),
            1.5,
            'Chapter 1.5',
            1,
            true,
            null
        );
        $manga->addChapter($existingChapter);
        $this->mangaRepository->save($manga);

        // Import the same chapter with CBZ
        $cbzBinary = $this->createValidCbzBinary();
        $command = new ImportChapter(
            mangaId: $mangaId,
            chapterNumber: 1.5,
            fileBinary: $cbzBinary
        );

        // Act
        $this->handler->handle($command);

        // Assert
        $updatedChapter = $this->mangaRepository->findChapterById('chapter-123');
        $this->assertNotNull($updatedChapter);
        $this->assertEquals('chapter-123', $updatedChapter->getId());
        $this->assertEquals($mangaId, $updatedChapter->getMangaId()->getValue());
        $this->assertEquals(1.5, $updatedChapter->getNumber());
        $this->assertEquals('Chapter 1.5', $updatedChapter->getTitle());
        $this->assertEquals(1, $updatedChapter->getVolume());
        $this->assertTrue($updatedChapter->isVisible());
        $this->assertTrue($updatedChapter->isAvailable());
        $this->assertNotNull($updatedChapter->getPagesDirectory());
    }

    public function test_it_throws_exception_when_manga_not_found(): void
    {
        // Arrange
        $cbzBinary = $this->createValidCbzBinary();
        $command = new ImportChapter(
            mangaId: 'non-existent-manga',
            chapterNumber: 1.0,
            fileBinary: $cbzBinary
        );

        // Assert
        $this->expectException(MangaNotFoundException::class);

        // Act
        $this->handler->handle($command);
    }

    public function test_it_throws_exception_when_file_is_not_valid_cbz(): void
    {
        // Arrange
        $mangaId = 'manga-123';
        $manga = new Manga(
            new MangaId($mangaId),
            new MangaTitle('One Piece'),
            new MangaSlug('one-piece'),
            'Description',
            'Eiichiro Oda',
            1997,
            ['action', 'adventure'],
            'ongoing'
        );
        $this->mangaRepository->save($manga);

        $invalidBinary = 'This is not a CBZ file';
        $command = new ImportChapter(
            mangaId: $mangaId,
            chapterNumber: 1.0,
            fileBinary: $invalidBinary
        );

        // Assert
        $this->expectException(\InvalidArgumentException::class);
        $this->expectExceptionMessage('The provided file is not a valid CBZ file');

        // Act
        $this->handler->handle($command);
    }

    private function createValidCbzBinary(): string
    {
        $tmpFile = tempnam(sys_get_temp_dir(), 'cbz');
        unlink($tmpFile);

        $zip = new \ZipArchive();
        if ($zip->open($tmpFile, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) !== true) {
            throw new \RuntimeException('Cannot create test CBZ file');
        }

        $zip->addFromString('image1.jpg', 'fake-image-data');
        $zip->close();

        $binaryContent = file_get_contents($tmpFile);
        unlink($tmpFile);

        return $binaryContent;
    }
}
