<?php

namespace Dalten\RuianToUir\Command;

use Dalten\RuianToUir\Command\Helper\FileResolver;
use Dalten\RuianToUir\Converter\ConverterInterface;
use Dalten\RuianToUir\Formatter\PlainText;
use Dalten\RuianToUir\Formatter\Sql;
use Dalten\RuianToUir\Writer\MultipleFiles;
use Dalten\RuianToUir\Writer\PrintOut;
use Dalten\RuianToUir\Writer\WriterInterface;
use Symfony\Component\Console\Command\Command as BaseCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

class Convert extends BaseCommand
{
    /**
     * Convert constructor.
     *
     * @param FileResolver         $fileResolver
     * @param ConverterInterface[] $converters
     * @param string[]             $skippedTags
     */
    public function __construct(
        private readonly FileResolver $fileResolver,
        private readonly array $converters,
        private readonly array $skippedTags)
    {
        parent::__construct();
    }

    public function execute(InputInterface $input, OutputInterface $output): int
    {
        if ('sql' === $input->getOption('data-format')) {
            $formatter = new Sql();
        } else {
            $formatter = new PlainText();
        }

        switch ($input->getOption('output-format')) {
            case 'directory':
                $extension = $formatter instanceof Sql ? 'sql' : 'txt';
                /** @var string $directory */
                $directory = $input->getOption('output-directory');
                $writer = new MultipleFiles($formatter, (string) $directory, $extension);

                break;
            case 'print':
                $writer = new PrintOut($formatter);

                break;
            default:
                throw new \Exception('Output formát "%s" nebyl rozpoznán. Známé formáty: ["print", "directory"].');
        }

        /** @var string $inputFile */
        $inputFile = $input->getArgument('input-file');
        $files = $this->fileResolver->resolveFiles($inputFile);

        $io = new SymfonyStyle($input, $output);

        if ($output->getVerbosity() > OutputInterface::VERBOSITY_QUIET) {
            $progress = $io->createProgressBar(\count($files) - 1);
            $progress->start();
        }

        foreach ($files as $file) {
            try {
                $filename = (string) $file;
                $io->writeln(['# '.$filename, '']);

                $this->handleFile($filename, $writer);

                if (isset($progress)) {
                    $progress->advance();
                }
            } catch (\Exception $e) {
                $io->error($e->getMessage());

                return 1;
            }
        }

        if (isset($progress)) {
            $progress->finish();
        }

        return 0;
    }

    protected function configure(): void
    {
        $this->setName('convert');
        $this->setDescription('Převede XML soubor ze vstupu do formátu UIR.');
        $this->addArgument(
            'input-file', InputArgument::REQUIRED, 'Zdroj dat (soubor, adresář, maska adresáře app/cache/*/).'
        );
        $this->addOption('data-format', null, InputOption::VALUE_REQUIRED, 'Formát dat (text, sql)', 'text');
        $this->addOption(
            'output-format', null, InputOption::VALUE_REQUIRED, 'Formát výstupu (print, directory)', 'print'
        );
        $this->addOption(
            'output-directory', null, InputOption::VALUE_REQUIRED, 'Cílový adresář (pro output-format=directory)',
            './output'
        );
    }

    /**
     * @param string          $filename
     * @param WriterInterface $writer
     */
    private function handleFile(string $filename, WriterInterface $writer): void
    {
        $reader = new \XMLReader();
        if (false === $reader->open($filename)) {
            throw new \InvalidArgumentException(\sprintf('Soubor %s nelze otevřít!', $filename));
        }

        while ($reader->read()) {
            while (\in_array($reader->name, $this->skippedTags)) {
                $reader->next();
            }

            if (\XMLReader::ELEMENT === $reader->nodeType) {
                foreach ($this->converters as $converter) {
                    if ($converter->accepts($reader)) {
                        $convertedData = $converter->convert($reader);
                        $writer->write($convertedData, $converter->getName());
                    }
                }
            }
        }

        $reader->close();
    }
}
