<?php
declare(strict_types=1);

namespace Autogedal\EanTools\Model\Tool;

use Autogedal\EanTools\Model\ResultStorage;
use Magento\Framework\Lock\LockManagerInterface;
use Psr\Log\LoggerInterface;
use Throwable;

class ExportProcessor
{
    private const LOCK_NAME = 'autogedal_ean_tools_export_queue';

    public function __construct(
        private readonly ResultStorage $storage,
        private readonly Exporter $exporter,
        private readonly Validator $validator,
        private readonly LockManagerInterface $lockManager,
        private readonly LoggerInterface $logger
    ) {
    }

    public function processNext(): void
    {
        if (!$this->lockManager->lock(self::LOCK_NAME, 0)) {
            return;
        }

        try {
            $runId = $this->storage->getNextQueuedRunId();
            if ($runId === null || !$this->storage->markProcessing($runId)) {
                return;
            }

            $this->process($runId);
        } finally {
            $this->lockManager->unlock(self::LOCK_NAME);
        }
    }

    private function process(string $runId): void
    {
        $manifest = $this->storage->readManifest($runId);
        $tool = (string)($manifest['tool'] ?? '');
        $format = (string)($manifest['format'] ?? '');
        $request = (array)($manifest['request'] ?? []);

        try {
            match ($tool) {
                'used' => $this->exporter->exportUsed($format, $runId),
                'invalid' => $this->exporter->exportInvalid($format, $runId),
                'duplicates' => $this->exporter->exportDuplicates($format, $runId),
                'missing' => $this->exporter->exportMissing((array)($request['filters'] ?? []), $format, $runId),
                'validator' => $this->processValidation($runId, $request, $format),
                default => throw new \UnexpectedValueException('Unknown EAN Tools export type: ' . $tool),
            };
        } catch (Throwable $exception) {
            $this->logger->error(
                'Autogedal_EanTools queued export failed: ' . $exception->getMessage(),
                ['exception' => $exception, 'run_id' => $runId, 'tool' => $tool]
            );
            $this->storage->fail($runId, $this->getFailureMessage($tool));
        }
    }

    private function processValidation(string $runId, array $request, string $format): string
    {
        $inputFile = (string)($request['input_file'] ?? '');

        try {
            return $this->validator->run(
                $this->storage->getInputFilePath($runId, $inputFile),
                isset($request['input_name']) ? (string)$request['input_name'] : null,
                $format,
                $runId
            );
        } finally {
            $this->storage->removeInputFile($runId, $inputFile);
        }
    }

    private function getFailureMessage(string $tool): string
    {
        return match ($tool) {
            'used' => (string)__('The export of used EANs could not be generated.'),
            'invalid' => (string)__('The export of products with invalid EANs could not be generated.'),
            'duplicates' => (string)__('The export of duplicate EANs could not be generated.'),
            'missing' => (string)__('The list of products without EANs could not be generated.'),
            'validator' => (string)__('The EAN code file could not be validated.'),
            default => (string)__('The file could not be generated.'),
        };
    }
}
