<?php

namespace Dalten\RuianToUir\Command;

use Dalten\RuianToUir\Command\Helper\FileDownloader;
use Dalten\RuianToUir\Converter\Municipality;
use Symfony\Component\Console\Command\Command;
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;

/**
 * Created by PhpStorm.
 * User: karel
 * Date: 23.02.2017
 * Time: 11:44.
 */
class GetFileList extends Command
{
    const DATA_SET_FULL = 'full';
    const DATA_SET_DIFF = 'diff';

    private $topLevelFullDataPath;
    private $municipalityFullDataPathPattern;
    private $changeDataPathPattern;
    /**
     * @var Municipality
     */
    private $municipalityConverter;
    /**
     * @var array
     */
    private $skippedTags;
    /**
     * @var FileDownloader
     */
    private $downloader;

    /**
     * GetFileList constructor.
     *
     * @param FileDownloader $downloader
     * @param Municipality   $municipalityConverter
     * @param array          $skippedTags
     * @param string         $topLevelFullDataPath
     * @param string         $municipalityFullDataPathPattern
     * @param string         $changeDataPathPattern
     */
    public function __construct(FileDownloader $downloader, Municipality $municipalityConverter, array $skippedTags,
        $topLevelFullDataPath, $municipalityFullDataPathPattern, $changeDataPathPattern)
    {
        $this->topLevelFullDataPath = $topLevelFullDataPath;
        $this->municipalityFullDataPathPattern = $municipalityFullDataPathPattern;
        $this->changeDataPathPattern = $changeDataPathPattern;
        $this->municipalityConverter = $municipalityConverter;
        $this->skippedTags = $skippedTags;
        $this->downloader = $downloader;
        parent::__construct();
    }

    protected function configure()
    {
        $this->setName('get-file-list');
        $this->setDescription('Získá seznam souborů ke stažení.');
        $this->addArgument(
            'data-set', InputArgument::REQUIRED, 'Celý import a nebo jen změnové soubory? (full, diff.)'
        );
        $this->addOption(
            'from-date', null, InputOption::VALUE_REQUIRED, 'Zahrnout změnové soubory od? (DD.MM.YYYY)',
            date('d.m.Y')
        );
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        /** @var string $type */
        $type = $input->getArgument('data-set');
        $io = new SymfonyStyle($input, $output);
        $verbose = $output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE;

        if (self::DATA_SET_FULL === $type) {
            try {
                $this->printFullDataList($io, $verbose);

                return 0;
            } catch (\Exception $e) {
                $error = $e->getMessage();
            }
        } elseif (self::DATA_SET_DIFF === $type) {
            try {
                $startDate = (string) $input->getOption('from-date');
                if (preg_match('~^\d{1,2}\.\d{1,2}\.\d{4}$~', $startDate)) {
                    if ($verbose) {
                        $io->warning(
                            'Předávání data ve formátu d.m.Y je deprecated a bude odstraněno. Používejte Y-m-d.'
                        );
                    }
                    /** @deprecated Podporu formátu d.m.Y ukončit ve v2. */
                    $startDate = date('Y-m-d', strtotime($input->getOption('from-date')));
                } elseif (!preg_match('~^\d{4}-\d{2}-\d{2}~', $startDate)) {
                    $io->error('Nesprávný formát data. Použijte formát YYYY-MM-DD.');
                    return 1;
                }

                $this->printDiffDataList($io, $startDate, $verbose);
                return 0;
            } catch (\Exception $e) {
                $error = $e->getMessage();
            }
        } else {
            $error = sprintf('Neplatný typ importu "%s". [%s, %s]', $type, self::DATA_SET_DIFF, self::DATA_SET_FULL);
        }

        $io->error($error);

        return 1;
    }

    private function printFullDataList(SymfonyStyle $io, $verbose = false)
    {
        $filename = $this->topLevelFullDataPath;
        if ($verbose) {
            $io->comment(sprintf('Stahuji "%s"', $filename));
        }
        $countyXmlPath = $this->downloader->getFirstLineFromFile($filename);

        $io->writeln($countyXmlPath);

        if ($verbose) {
            $io->comment(sprintf('Stahuji "%s"', $countyXmlPath));
        }
        $tempPath = $this->downloader->downloadAndGunzipFileToTemp($countyXmlPath);

        if ($verbose) {
            $io->comment(sprintf('Staženo a rozbaleno do "%s"', $tempPath));
        }

        $municipalityIds = $this->getMunicipalityIds($tempPath, $io, $verbose);
        unlink($tempPath);

        $template = null; // http://vdp.cuzk.cz/vymenny_format/soucasna/20170131_OB_569054_UZSZ.xml.gz
        foreach ($municipalityIds as $municipalityId) {
            $municipalityId = (string) $municipalityId;
            if (!isset($template)) {
                $uri = str_replace('%obec_kod%', $municipalityId, $this->municipalityFullDataPathPattern);
                if ($verbose) {
                    $io->comment(sprintf('Stahuji "%s"', $uri));
                }
                $path = $this->downloader->getFirstLineFromFile($uri);
                $template = str_replace('_'.$municipalityId.'_', '_%obec_kod%_', $path);
                if ($verbose) {
                    $io->comment(sprintf('Cesta pro data obce: "%s"', $template));
                }
            } else {
                $path = str_replace('%obec_kod%', $municipalityId, $template);
            }
            $io->writeln($path);
        }
    }

    /**
     * @param string       $filename
     * @param SymfonyStyle $io
     * @param bool         $verbose
     *
     * @return int[]
     */
    private function getMunicipalityIds($filename, SymfonyStyle $io, $verbose = false)
    {
        $reader = new \XMLReader();
        if ($verbose) {
            $io->comment(sprintf('Otevírám "%s"', $filename));
        }
        if (false === $reader->open($filename)) {
            throw new \InvalidArgumentException(sprintf('Soubor %s nelze otevřít!', $filename));
        }

        $ids = [];

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

            if (\XMLReader::ELEMENT === $reader->nodeType) {
                if ($this->municipalityConverter->accepts($reader)) {
                    $data = $this->municipalityConverter->convert($reader);
                    if (!empty($data['obec_kod'])) {
                        $ids[] = $data['obec_kod'];
                    }
                }
            }
        }

        $reader->close();

        return $ids;
    }

    private function printDiffDataList(SymfonyStyle $io, $startDate, $verbose = false)
    {
        $filename = str_replace('%datum_od%', $startDate, $this->changeDataPathPattern);
        if ($verbose) {
            $io->comment(sprintf('Stahuji "%s"', $filename));
        }
        $content = $this->downloader->getFile($filename);

        if (false === $content) {
            throw new \RuntimeException(sprintf('Nepodařilo se stáhnout soubor "%s"', $filename));
        }

        $io->write((string) $content);
    }
}
