<?php
declare(strict_types=1);

namespace Autogedal\FrontendI18n\Console\Command;

use Autogedal\FrontendI18n\Model\TranslationComparator;
use Autogedal\FrontendI18n\Model\TranslationCsvReader;
use Magento\Framework\Console\Cli;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class FindDuplicateTranslationsCommand extends Command
{
    private const COMMAND_NAME = 'autogedal:i18n:duplicates';
    private const OPTION_CSV = 'csv';
    private const OPTION_OUTPUT = 'output';

    public function __construct(
        private readonly TranslationCsvReader $translationCsvReader,
        private readonly TranslationComparator $translationComparator,
        ?string $name = null
    ) {
        parent::__construct($name);
    }

    protected function configure(): void
    {
        $this->setName(self::COMMAND_NAME)
            ->setDescription('Find duplicate source phrases in a translation CSV file')
            ->setDefinition([
                new InputOption(
                    self::OPTION_CSV,
                    'c',
                    InputOption::VALUE_REQUIRED,
                    'Translation CSV to inspect'
                ),
                new InputOption(
                    self::OPTION_OUTPUT,
                    'o',
                    InputOption::VALUE_REQUIRED,
                    'CSV report path for duplicate rows'
                ),
            ]);
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        try {
            $csvPath = trim((string)$input->getOption(self::OPTION_CSV));
            if ($csvPath === '') {
                throw new \InvalidArgumentException('The --csv option is required.');
            }

            $rows = $this->translationCsvReader->readRows($csvPath);
            $duplicates = $this->translationComparator->duplicates($rows);
            $outputPath = trim((string)$input->getOption(self::OPTION_OUTPUT));
            if ($outputPath === '') {
                $baseName = pathinfo($csvPath, PATHINFO_FILENAME);
                $outputPath = BP . '/var/i18n/' . $baseName . '.duplicates.csv';
            }

            $this->writeReport($outputPath, $duplicates);

            $conflictingCount = count(array_filter($duplicates, static fn (array $row): bool => $row['status'] === 'duplicate-different'));
            $output->writeln('<info>Scanned ' . count($rows) . ' row(s).</info>');
            $output->writeln('<info>Found ' . count($duplicates) . ' duplicate row(s).</info>');
            $output->writeln('<info>Found ' . $conflictingCount . ' conflicting duplicate row(s).</info>');
            $output->writeln('<info>Duplicate report written to: ' . $outputPath . '</info>');

            return Cli::RETURN_SUCCESS;
        } catch (\InvalidArgumentException $e) {
            $output->writeln('<error>' . $e->getMessage() . '</error>');
            return Cli::RETURN_FAILURE;
        } catch (\Throwable $e) {
            $output->writeln('<error>' . $e->getMessage() . '</error>');
            return Cli::RETURN_FAILURE;
        }
    }

    /**
     * @param array<int,array{source:string,first_line:int,duplicate_line:int,first_translation:string,duplicate_translation:string,effective_translation:string,status:string}> $rows
     */
    private function writeReport(string $path, array $rows): void
    {
        $directory = dirname($path);
        if (!is_dir($directory) && !mkdir($directory, 0775, true) && !is_dir($directory)) {
            throw new \RuntimeException('Unable to create directory: ' . $directory);
        }

        $handle = fopen($path, 'wb');
        if ($handle === false) {
            throw new \RuntimeException('Unable to open output file: ' . $path);
        }

        fputcsv($handle, [
            'source',
            'first_line',
            'duplicate_line',
            'first_translation',
            'duplicate_translation',
            'effective_translation',
            'status',
        ]);

        foreach ($rows as $row) {
            fputcsv($handle, [
                $row['source'],
                (string)$row['first_line'],
                (string)$row['duplicate_line'],
                $row['first_translation'],
                $row['duplicate_translation'],
                $row['effective_translation'],
                $row['status'],
            ]);
        }

        fclose($handle);
    }
}
