<?php

namespace Dalten\RuianToUir\Command;

use Dalten\RuianToUir\Command\Helper\FileResolver;
use Dalten\RuianToUir\Converter\ConverterInterface;
use Dalten\RuianToUir\Converter\ExplorerWrapper;
use Symfony\Component\Console\Command\Command as BaseCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

class Explore extends BaseCommand
{
    /**
     * @var ExplorerWrapper[]
     */
    private readonly array $converters;

    /**
     * @param ConverterInterface[] $converters
     * @param string[]             $skippedTags
     */
    public function __construct(
        private readonly FileResolver $fileResolver,
        array $converters,
        private readonly array $skippedTags)
    {
        parent::__construct();

        $this->converters = array_map(
            static fn ($converter): ExplorerWrapper => new ExplorerWrapper($converter), $converters
        );
    }

    public function execute(InputInterface $input, OutputInterface $output): int
    {
        /** @var string $inputFile */
        $inputFile = $input->getArgument('input-file');
        $files = $this->fileResolver->resolveFiles($inputFile);
        $io = new SymfonyStyle($input, $output);

        foreach ($files as $file) {
            try {
                $io->comment((string) $file);
                $this->handleFile((string) $file, $io);
            } catch (\Exception $e) {
                $io->error($e->getMessage());

                return 1;
            }
        }

        return 0;
    }

    private function handleFile(string $filename, SymfonyStyle $io): void
    {
        $skippedTags = $this->skippedTags;

        $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, $skippedTags)) {
                $reader->next();
            }

            if (\XMLReader::ELEMENT === $reader->nodeType) {
                foreach ($this->converters as $converter) {
                    if ($converter->accepts($reader)) {
                        $skippedTags[] = $reader->name;
                        $data = $converter->convert($reader);
                        $io->title($converter->getName());

                        $depth = 1;
                        $io->writeln('');
                        $this->writeArray($io, $data->getData(), $depth);
                    }
                }
            }
        }

        $reader->close();
    }

    /**
     * @param array<scalar, mixed> $data
     */
    private function writeArray(SymfonyStyle $io, array $data, int $depth): void
    {
        foreach ($data as $key => $value) {
            $expand = false;
            $row = [str_pad('', $depth, '.'), $key, ': '];
            if (null === $value) {
                $row[] = '~';
            } elseif (\is_object($value)) {
                $row[] = $value::class;
            } elseif (\is_array($value)) {
                $expand = true;
                $row[] = $value ? '' : '[]';
            } elseif (\is_scalar($value)) {
                $row[] = "'$value'";
            } else {
                $row[] = '(unknown) '.\gettype($value);
            }

            $io->text(implode('', $row));
            if ($expand) {
                $this->writeArray($io, $value, $depth + 1);
            }
        }
    }

    protected function configure(): void
    {
        $this->setName('explore');
        $this->setDescription('Zobrazí přehledně strukturu jednotlivých prvků v XML souboru.');
        $this->addArgument(
            'input-file', InputArgument::REQUIRED, 'Zdroj dat (soubor, adresář, maska adresáře app/cache/*/).'
        );
    }
}
