<?php

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

use App\Domain\Manga\Application\Command\ImportVolume;
use App\Domain\Manga\Application\CommandHandler\ImportVolumeHandler;
use App\Domain\Manga\Domain\Exception\MangaNotFoundException;
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 ImportVolumeHandlerTest extends TestCase
{
    private InMemoryMangaRepository $mangaRepository;
    private InMemoryImageStorage $imageStorage;
    private ImportVolumeHandler $handler;

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

    public function test_it_updates_all_chapters_in_volume(): void
    {
        // Arrange
        $mangaId = 'manga-123';
        $volumeNumber = 1;
        $manga = new Manga(
            new MangaId($mangaId),
            new MangaTitle('One Piece'),
            new MangaSlug('one-piece'),
            'Description',
            'Eiichiro Oda',
            1997,
            ['action', 'adventure'],
            'ongoing'
        );
        // Create chapters in volume 1 and add through the aggregate
        for ($i = 1; $i <= 3; $i++) {
            $chapter = new Chapter(
                new ChapterId("chapter-$i"),
                new MangaId($mangaId),
                (float)$i,
                "Chapter $i",
                $volumeNumber,
                true,
                null
            );
            $manga->addChapter($chapter);
        }
        $this->mangaRepository->save($manga);

        $cbzBinary = $this->createValidCbzBinary();
        $command = new ImportVolume(
            mangaId: $mangaId,
            volumeNumber: $volumeNumber,
            fileBinary: $cbzBinary
        );

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

        // Assert
        $chapters = $this->mangaRepository->findChaptersByMangaIdAndVolume($mangaId, $volumeNumber);
        $this->assertCount(3, $chapters);

        foreach ($chapters as $chapter) {
            $this->assertTrue($chapter->isAvailable());
            $this->assertNotNull($chapter->getPagesDirectory());
        }
    }

    public function test_it_throws_exception_when_manga_not_found(): void
    {
        // Arrange
        $cbzBinary = $this->createValidCbzBinary();
        $command = new ImportVolume(
            mangaId: 'non-existent-manga',
            volumeNumber: 1,
            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 ImportVolume(
            mangaId: $mangaId,
            volumeNumber: 1,
            fileBinary: $invalidBinary
        );

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

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

    public function test_it_throws_exception_when_no_chapters_in_volume(): 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 ImportVolume(
            mangaId: $mangaId,
            volumeNumber: 999,
            fileBinary: $cbzBinary
        );

        // Assert
        $this->expectException(\InvalidArgumentException::class);
        $this->expectExceptionMessage('No chapters found');

        // 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;
    }
}
