<?php

namespace NPS\Factory;

use NPS\Repository\KnowledgeBaseRepository;
use NPS\DependencyInjection\IExpertSystemBridge;
use NPS\Model\User;
use NPS\Model\KnowledgeBase;
use NPS\Entity\KnowledgeBaseEntity;
use NPS\DependencyInjection\IKnowledgeBaseInfoProvider;
use NPS\Entity\IEntity;
use NPS\Repository\IObjectRepository;
use Doctrine\ORM\EntityManagerInterface;
use NPS\Etc\Files;
use Symfony\Component\Finder\Exception\AccessDeniedException;
use NPS\Etc\Strings;


/**
 * Knowledge base object factory 
 * @author Lukas Korinek
 */
class KnowledgeBaseFactory implements IObjectFactory
{
    use TMemorizedFactory;

    /** @var IKnowledgeBaseInfoProvider $provider */
    protected $provider;

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

    /** @var string $path Path to the source knowledge base directory */
    private $path;

    public function __construct(EntityManagerInterface $em, IKnowledgeBaseInfoProvider $provider, $basesPath)
    {
        $this->path = Files::normalizeDirectory($basesPath, Files::WRITEABLE);
        $this->provider = $provider;
        $this->em = $em;
    }

    /**
     * Gets the directory in which knowledge bases are stored
     * @return string without trailing slash
     */
    public function getKnowledgeBasesDirectory()
    {
        return $this->path;
    }

    /**
     * @inheritdoc
     */
    public function make(IEntity $entity)
    {
        return $this->load($entity, function($entity)
        {
            if(!$entity->getId())
            {
                $this->em->persist($entity);
            }

            return new KnowledgeBase($entity, $this->provider);            
        });
    }

    /**
     * Creates a new Knowledge base
     * @param string $name
     * @param string $content
     * @param int $bindId
     * @param \DateTime $version
     * @return KnowledgeBase|null
     */
    public function create($name, $content, $bindId, \DateTime $version = null)
    {
        $version = $version ?: new \DateTime();
        $path = $this->normalizeKnowledgeBasePath($name, $version);

        $dir = dirname($path);
        if(!is_dir($dir))
        {
            mkdir($dir, 0755); // Writeability of the folder ensured in the constructor
        }

        $base = KnowledgeBaseEntity::create([
            'path' => $path,
            'bindId' => $bindId,
            'dateCreated' => $version
        ]);

        if(!file_put_contents($path, $content))
        {
            throw new AccessDeniedException('Creation failed due to permission or storage issues');
        }

        return $this->make($base);
    }
    
    /**
     * Creates a normalized path to a knowledge base based on its name and version date
     * @param string $name
     * @param DateTime $version 
     * @return string
     */
    public function normalizeKnowledgeBasePath($name, \DateTime $version = null)
    {
        $name = Strings::sanitizeASCII($name);
        $version = $version ?: new \DateTime();
        
        return sprintf('%s/%s/%s.nps', $this->getKnowledgeBasesDirectory(), $name, $version->format('Ymd'));
    }
}

