<?php

namespace App\Domain\Conversion\Infrastructure\Service;

use App\Domain\Conversion\Domain\Contract\ConversionServiceInterface;
use App\Domain\Conversion\Domain\Exception\ConversionException;
use App\Domain\Conversion\Domain\Model\ConversionRequest;
use App\Domain\Conversion\Domain\Model\ConversionResult;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Process\Process;

final class ConversionService implements ConversionServiceInterface
{
    private readonly string $tempDir;
    private readonly Filesystem $filesystem;

    public function __construct(string $projectDir)
    {
        $this->tempDir = $projectDir . '/public/tmp';
        $this->filesystem = new Filesystem();
    }

    public function convert(ConversionRequest $request): ConversionResult
    {
        try {
            $convertedFilePath = $this->convertCbrToCbz($request->getFilePath());

            $convertedFileSize = file_exists($convertedFilePath) ? filesize($convertedFilePath) : 0;

            return new ConversionResult(
                convertedFilePath: $convertedFilePath,
                outputFilename: $request->getOutputFilename(),
                originalFileSize: $request->getFileSize(),
                convertedFileSize: $convertedFileSize
            );
        } catch (\Exception $e) {
            throw ConversionException::conversionFailed($e->getMessage());
        }
    }

    private function convertCbrToCbz(string $cbrPath): string
    {
        $tempDir = $this->tempDir . '/' . uniqid('cbr_conversion_');
        $this->filesystem->mkdir($tempDir);

        $extractDir = $tempDir . '/extract';
        $this->filesystem->mkdir($extractDir);

        // Essayer d'extraire avec unrar-free
        $process = new Process(['unrar-free', 'x', $cbrPath, $extractDir]);
        $process->run();

        // Si unrar échoue, essayer avec 7z
        if (!$process->isSuccessful()) {
            $process = new Process(['7z', 'x', $cbrPath, "-o$extractDir"]);
            $process->run();

            if (!$process->isSuccessful()) {
                throw new \RuntimeException("Extraction failed: " . $process->getErrorOutput());
            }
        }

        // Créer le CBZ
        $cbzFileName = pathinfo($cbrPath, PATHINFO_FILENAME) . '.cbz';
        $cbzPath = $this->tempDir . '/' . $cbzFileName;
        $zip = new \ZipArchive();
        if ($zip->open($cbzPath, \ZipArchive::CREATE) !== true) {
            throw new \RuntimeException("Cannot create ZIP file");
        }

        $files = new \RecursiveIteratorIterator(
            new \RecursiveDirectoryIterator($extractDir),
            \RecursiveIteratorIterator::LEAVES_ONLY
        );

        foreach ($files as $file) {
            if (!$file->isDir()) {
                $filePath = $file->getRealPath();
                $relativePath = substr($filePath, strlen($extractDir) + 1);
                $zip->addFile($filePath, $relativePath);
            }
        }

        $zip->close();

        // Nettoyer le dossier temporaire d'extraction
        $this->filesystem->remove($tempDir);

        return $cbzPath;
    }
}
