<?php

namespace NPS\Factory;

use NPS\Model\User;
use NPS\Repository\UserRepository;
use NPS\Entity\UserEntity;
use NPS\Entity\IEntity;
use NPS\DependencyInjection\EventDispatcher;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use NPS\Etc\Strings;
use NPS\Entity\PasswordResetTokenEntity;
use NPS\Entity\UserActivationTokenEntity;
use NPS\Model\UserActivationToken;
use NPS\Model\PasswordResetToken;
use NPS\Model\AbstractToken;
use NPS\DependencyInjection\Mailer;
use Symfony\Component\HttpFoundation\RequestStack;


/**
 * Token object factory 
 * @author Lukas Korinek
 */
class TokenFactory implements IObjectFactory
{
    use TMemorizedFactory;

    const TOKEN_PASSWORD_RESET = 'password_reset';
    const TOKEN_USER_ACTIVATION = 'user_activation';

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

    /** @var UserFactory $userFactory */
    protected $userFactory;

    /** @var Mailer $mailer */
    protected $mailer;

    /** @var int $tokenTTL */
    protected $tokenTTL;

    public function __construct(EntityManagerInterface $em, UserFactory $userFactory, Mailer $mailer, $tokenTTL)
    {
        $this->em = $em;
        $this->userFactory = $userFactory;
        $this->mailer = $mailer;
        $this->tokenTTL = $tokenTTL;
    }

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

            $user = $this->userFactory->make($entity->user);

            if($entity instanceof PasswordResetTokenEntity)
            {
                return new PasswordResetToken($entity, $user, $this->tokenTTL);
            }
            else if($entity instanceof UserActivationTokenEntity)
            {
                return new UserActivationToken($entity, $user, $this->tokenTTL);
            }
            
            throw new \InvalidArgumentException('The entity ' . get_class($entity) . ' is not a valid entity for TokenFactory');
        });
    }

    
    /**
     * Creates a new token
     * @param string $type Target token type, refer to constants in this class
     * @param string $backlink Backlink to the token verification URL
     * @param User $user
     * @return AbstractToken
     */
    public function create($type, $backlink, User $user)
    {
        switch($type)
        {
            case self::TOKEN_PASSWORD_RESET:
            {
                $entity = PasswordResetTokenEntity::create([
                    'user' => $user->getEntity(),
                    'hash' => Strings::generateHash([$type, $user->getId()])
                ]);
                
                // Create an email
                $this->mailer->mail(
                    $user->getEmail(),
                    'password_reset',
                    'password.html.twig',
                    [
                        'token' => $entity,
                        'user' => $user,
                        'backlink' => Strings::urlQuery($backlink, ['token' => $entity->hash])
                    ]
                );

                break;
            }
            case self::TOKEN_USER_ACTIVATION:
            {
                $entity = UserActivationTokenEntity::create([
                    'user' => $user->getEntity(),
                    'hash' => Strings::generateHash([$type, $user->getId()])
                ]);

                // Create an email
                $this->mailer->mail(
                    $user->getEmail(),
                    'user_activation',
                    'activation.html.twig',
                    [
                        'token' => $entity,
                        'user' => $user,
                        'backlink' => Strings::urlQuery($backlink, ['token' => $entity->hash])
                    ]
                );

                break;
            }
            default: 
            {
                throw new \InvalidArgumentException('Invalid token type passed');
            }
        }

        return $this->make($entity);
    }


}

