<?php 

namespace NPS\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Doctrine\ORM\EntityManagerInterface;
use NPS\DependencyInjection\IKnowledgeBaseInfoProvider;
use NPS\Etc\Strings;
use NPS\Model\KnowledgeBase;
use NPS\Repository\KnowledgeBaseRepository;
use NPS\Factory\KnowledgeBaseFactory;



/**
 * Adds or updates a knowledge base from a file
 * @author Lukas Korinek
 */
class AddBaseCommand extends Command
{

    /** @var KnowledgeBaseRepository $repo  */
    private $repo;

    /** @var KnowledgeBaseFactory $factory */
    private $factory;

    /** @var IKnowledgeBaseInfoProvider $provider */
    private $nameProvider;

    /** @var EntityManagerInterface $em */
    private $em;

    /** @var string $locale */
    private $locale;

    public function __construct(EntityManagerInterface $em, KnowledgeBaseRepository $repo, KnowledgeBaseFactory $factory, IKnowledgeBaseInfoProvider $nameProvider, $locale)
    {
        $this->nameProvider = $nameProvider;
        $this->repo = $repo;
        $this->factory = $factory;
        $this->em = $em;
        $this->defaultLocale = $locale;

        parent::__construct();
    }

    /**
     * @inheritdoc
     */
    protected function configure()
    {
        $this 
            ->setName('base:add')
            ->setDescription('Adds or updates a knowledge base from a file')
            ->addOption('update', null, InputOption::VALUE_NONE, 'Will update content of a base which exists already')
            ->addOption('ver', null, InputOption::VALUE_REQUIRED, 'Version of the knowledge base in format Ymd')
            ->addOption('status', null, InputOption::VALUE_REQUIRED, 'Status of the knowledge base')
            ->addArgument('path', InputArgument::REQUIRED);
    }   

    /**
     * @inheritdoc
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        // Normalize target base path
        $path = $input->getArgument('path');
        if(!Strings::contains('.nps', $path))
        {
            $path = $this->factory->getKnowledgeBasesDirectory() . '/' . $path . '.nps';
        }

        // Obtain knowledge base content
        $output->writeln('Knowledge base: ' . $path);
        $content = file_get_contents($path);


        // Obtain name of the knowledge base in a default language
        $supported = $this->nameProvider->getKnowledgeBaseLanguages($path);
        if(!$supported)
        {
            $output->writeln('Name of the base could not be resolved');
            return 1;
        }

        $language = null;
        foreach($supported as $locale)
        {
            if(Strings::contains($this->locale, $locale))
            {
                $language = $locale;
            }
        }

        if(!$language)
        {
            $language = reset($supported);
        }

        $this->nameProvider->setDefaultLanguage($language);
        $name = $this->nameProvider->getKnowledgeBaseName($path);
        if(!$name)
        {
            $output->writeln('Name of the base could not be resolved');
            return 1;
        }

        // Obtain version
        $version = trim($input->getOption('ver')) ?: date('Ymd');
        $version = \DateTime::createFromFormat('Ymd', $version);
        if(!$version)
        {
            $output->writeln('Invalid version string argument passed');
            return 1;
        }

        // Check version for boundaries
        if($version->getTimestamp() > time() || $version->getTimestamp() < time() - 5 * 365 * 24 * 3600)
        {
            $output->writeln('Date in the name of a knowledge base cannot be in a distant past or any future. Please use yyyymmdd format.');
            return 1;
        }

        // Obtain status
        $statusString = trim(strtoupper($input->getOption('status'))) ?: null;
        $reflection = new \ReflectionClass(KnowledgeBase::class);
        $constants = $reflection->getConstants();
        if($statusString && !array_key_exists($statusString, $constants))
        {
            $output->writeln('Invalid status argument passed');
            return 1;
        }
        $status = $statusString ? $constants[$statusString] : null;

        // Handle existing knowledge base for a non updating command call
        $update = !!$input->getOption('update');
        $base = $this->repo->getKnowledgeBaseByNameAndVersion($name, $version);
        if($base && !$update)
        {
            $output->writeln('The base already exists');
            return 2;
        }

        // Update content for an existing base
        else if($base && $update)
        {
            $base->updateContent($content);
            $this->em->flush();
            $this->repo->clearCache();

            if($output->isVerbose())
            {
                $output->writeln("Updated a knowledge base \"{$base->getPath()}\"");
            }
            else
            {
                $output->writeln('Updated');
                $output->writeln($base->getId());
            }
        }

        // Create a base which doesn't exist
        else if(!$base)
        {
            $base = $this->factory->create($name, $content, $this->repo->getBindIdByName($name), $version);
            $this->em->flush();
            $this->repo->clearCache();

            if($output->isVerbose())
            {
                $output->writeln("Created a knowledge base \"{$base->getPath()}\"");
            }
            else
            {
                $output->writeln('Created');
                $output->writeln($base->getId());
            }
        }

        // Update status of the base
        if($status)
        {
            $base->setStatus($status);
            
            $this->em->flush();
            $this->repo->clearCache();
        }
        
        return 0;
    }

    
}


