<?php
namespace Backend\BaseBundle\Controller\Backend;

use Backend\BaseBundle\Form\Type\resetPasswordType;
use Backend\BaseBundle\Model\SiteUser;
use ReCaptcha\ReCaptcha;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Backend\BaseBundle\Model;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;

class SecurityController extends Controller
{
    /**
     * @Route("/login", name="@BackendLogin")
     * @Method({"GET"})
     * @Template()
     */
    public function loginAction(Request $request)
    {
        $session = $request->getSession();
        $authErrorKey = Security::AUTHENTICATION_ERROR;
        $lastUsernameKey = Security::LAST_USERNAME;

        if ($request->attributes->has($authErrorKey)) {
            $error = $request->attributes->get($authErrorKey);
        } elseif (null !== $session && $session->has($authErrorKey)) {
            $error = $session->get($authErrorKey);
            $session->remove($authErrorKey);
        } else {
            $error = null;
        }

        if (!$error instanceof AuthenticationException) {
            $error = null; // The value does not come from the security component.
        }

        // last username entered by the user
        $lastUsername = (null === $session) ? '' : $session->get($lastUsernameKey);
        $csrfToken = $this->get('security.csrf.token_manager')->getToken('authenticate')->getValue();

        return array(
            'last_username' => $lastUsername,
            'error' => $error,
            'csrf_token' => $csrfToken,
        );
    }

    /**
     * @Route("/logincheck", name="@BackendLoginCheck")
     * @Method({"POST"})
     */
    public function loginCheckAction(Request $request, Model\Site $site)
    {
    }

    /**
     * @Route("/logout", name="@BackendLogout")
     */
    public function logoutAction()
    {
    }

    protected function getRecaptchaConfig()
    {
        $slug = $this->get('request')->attributes->get('slug');
        $site = Model\SiteQuery::create()
            ->findOneBySlug($slug);
        if(!$site){
            return null;
        }
        $config = $this->get('backend_base.site_config_builder')->build($site->getId())->get('system');

        if(!isset($config['recaptcha_site_key']) || !isset($config['recaptcha_secret_key'])){
            return null;
        }
        return array(
            'recaptcha_site_key' => $config['recaptcha_site_key'],
            'recaptcha_secret_key' => $config['recaptcha_secret_key'],
        );
    }

    /**
     * @Route("/forgetpassword", name="@BackendForgetPassword")
     * @Method({"GET"})
     * @Template()
     */
    public function forgetPasswordAction(Request $request)
    {
        $config = $this->getRecaptchaConfig();
        return array('recaptchaConfig' => $this->getRecaptchaConfig());
    }

    /**
     * @Route("/forgetpassword")
     * @Method({"POST"})
     */
    public function forgetPasswordPOSTAction(Request $request, $slug)
    {
        /** @var Model\SiteUser $user */
        $user = null;
        $validator = $this->get('validator');
        $constraints = new Assert\Collection(array(
           'email' => array(
               new Assert\NotBlank(),
               new Assert\Email(),
               new Assert\Callback(array(
                   'callback' => function($email, ExecutionContextInterface $context) use(&$user, $slug){
                       $user = Model\SiteUserQuery::create()
                           ->filterByEmail($email) //第1個查詢條件
                           ->useSiteQuery()  //切換到site_user去關聯查詢slug
                               ->filterBySlug($slug) //查詢slug
                           ->endUse() //要結束查尋並切換到原來的SQL
                           ->findOne() //找出一筆
                           ;
                       if(!$user){
                           $context->addViolation('email verify fail');
                       }
                   },
               )),
           ),
           'g-recaptcha-response' => array(
               new Assert\Callback(array(
                   'callback' => function($recaptchaResponse, ExecutionContextInterface $context){
                       if($this->get('kernel')->getEnvironment() == 'test'){
                           return;
                       }
                       $config = $this->getRecaptchaConfig();
                       $recaptcha = new ReCaptcha($config['recaptcha_secret_key']);
                       $result = $recaptcha->verify($recaptchaResponse);
                       if(!$result->isSuccess()){
                           $context->addViolation('captcha verify fail');
                       }
                   }
               ))
           ),
        ));
        $errors = $validator->validate($request->request->all(), $constraints);
        if(count($errors) > 0){
            $this->addFlash('error', 'message.data.error.bad_email');
            return $this->redirectToRoute('@BackendForgetPassword', array(
                'slug' => $slug,
            ));
        }
        $user->generateToken();
        $user->save();
        $this->sendforgetpasswordEmail($user);
        $request->getSession()->getFlashBag()->add('success', 'message.data.success.forgetpassword_mail_send');
        return $this->redirectToRoute('@BackendLogin', array('slug' => $slug));

    }

    /**
     * @Route("/forgetpasswordcheck/{email}/{token}")
     * @Method({"GET"})
     */
    public function forgetPasswordCheckTokenAction($email, $token, $slug, Request $request)
    {

        $user = Model\SiteUserQuery::create()
            ->filterByEmail($email)
            ->filterByConfirmToken($token)
            ->filterByTokenExpiredAt(time(), \Criteria::GREATER_THAN)
            ->useSiteQuery()
                ->filterBySlug($slug)
            ->endUse()
            ->findOne();
        if(!$user){
            throw $this->createNotFoundException();
        }
        $request->getSession()->set('resetpassworduser', $user);
        return $this->redirectToRoute('backend_base_backend_security_resetpassword', array('slug' => $slug));
    }

    /**
     * @Route("/resetpassword")
     * @Template()
     */
    public function resetPasswordAction(Request $request, $slug)
    {
        $user = $request->getSession()->get('resetpassworduser');

        if(!$user){
            throw $this->createNotFoundException();
        }

        $form = $this->createForm(new resetPasswordType(), $user);
        $form->handleRequest($request);

        if($form->isValid()){
            /** @var $user SiteUser */
            $user->setConfirmToken(null);
            $user->setTokenExpiredAt(null);
            $this->get('site_user_manager')->updateUser($user);
            $request->getSession()->remove('resetpassworduser');
            $request->getSession()->getFlashBag()->add('success', 'message.data.success.password_reset');
            return $this->redirectToRoute('@BackendLogin', array('slug' => $slug));
        }

        return array(
            'passwordForm' => $form->createView(),
        );

    }

    protected function sendforgetpasswordEmail(Model\SiteUser $user)
    {
        $user->getConfirmToken();
        $user->getTokenExpiredAt();
        $mailContent = $this->renderView("BackendBaseBundle:Backend/Mail:forgetPasswordMail.html.twig", array(
            'user' => $user,
        ));
        $mailerService = $this->get('site_custom_mailer');
        $message = $mailerService->newMessage($user->getSiteId());
        $message
            ->setSubject('忘記密碼確認信')
            ->setTo(array(
                $user->getEmail() => $user->getLoginName(),
            ))
            ->setBody($mailContent)
            ->setContentType('text/html')
            ;
        $mailerService->get($user->getSiteId())->send($message);
    }
}
