<?php

namespace App\Controller\Admin;

use App\Enum\Role;
use App\Entity\User;
use App\Traits\LanguagesTrait;
use App\Controller\Admin\CrudController;
use Doctrine\ORM\EntityManagerInterface;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
use EasyCorp\Bundle\EasyAdminBundle\Config\Filters;
use EasyCorp\Bundle\EasyAdminBundle\Field\FormField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField;
use Symfony\Contracts\Translation\TranslatorInterface;
use EasyCorp\Bundle\EasyAdminBundle\Field\BooleanField;
use EasyCorp\Bundle\EasyAdminBundle\Filter\ChoiceFilter;
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
use EasyCorp\Bundle\EasyAdminBundle\Field\DateField;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;

class UserCrudController extends CrudController
{
    use LanguagesTrait;
    private UserPasswordHasherInterface $userPasswordHasher;


    public function __construct (ParameterBagInterface $params, EntityManagerInterface $em,
                                 AdminContextProvider $context, ValidatorInterface $validator,
                                 TranslatorInterface $translator, AdminUrlGenerator $adminUrlGenerator,
                                 UserPasswordHasherInterface $userPasswordHasher)
    {
        parent::__construct($params, $em, $context, $validator, $translator, $adminUrlGenerator);
        $this->userPasswordHasher = $userPasswordHasher;
    }


    public static function getEntityFqcn (): string
    {
        return User::class;
    }


    public function configureCrud (Crud $crud): Crud
    {
        return $crud
            ->setEntityLabelInSingular($this->trans('user.labelInSingular'))
            ->setEntityLabelInPlural($this->trans('user.labelInPlural'))
            ->setSearchFields(['email', 'name', 'phone']);
    }


    public function configureActions (Actions $actions): Actions
    {
        return $actions
            ->add(Crud::PAGE_INDEX, Action::DETAIL);
    }

    public function configureFilters(Filters $filters): Filters
    {
        // FIXFER
        return $filters
            ->add(ChoiceFilter::new('roles')
            ->setChoices(array_flip(Role::ROLES))
            ->canSelectMultiple()
            ->renderExpanded()
        );
    }

    public function configureFields (string $pageName): iterable
    {
        $panelInfo = FormField::addPanel($this->trans('user.panel.personalInfo'));
        $email = TextField::new('email')
            ->setLabel($this->trans('user.configureFields.email'))
            ->setColumns('col-md-6 col-xl-3');

        $firstName = TextField::new('name')
            ->setLabel($this->trans('user.configureFields.name'))
            ->setRequired(true)
            ->setColumns('col-md-6 col-xl-3');

        $phone = TextField::new('phone')
            ->setLabel($this->trans('user.configureFields.phone'))
            ->setRequired(true)
            ->setColumns('col-md-6 col-xl-3');

        $panelAccess = FormField::addPanel($this->trans('user.panel.access'));

        $password = TextField::new('plainPassword')
            ->setLabel($this->trans('user.configureFields.password'))
            ->setFormType(PasswordType::class)
            ->setRequired(false)
            ->setFormTypeOption('empty_data', '')
            ->setColumns('col-md-6 col-xl-3');

        $roles = ChoiceField::new('roles')
            ->setChoices(array_flip(User::ROLES))
            ->allowMultipleChoices(true)
            ->setLabel($this->trans('user.configureFields.roles'))
            ->setColumns('col-md-6 col-xl-3');

        $active = BooleanField::new('isActive')
            ->setColumns('col-md-6 col-xl-3')
            ->setLabel($this->trans('user.configureFields.isActive'))
        ;

        $lastLogin = DateField::new('lastLogin')
            ->setColumns('col-md-6 col-xl-3')
            ->setLabel($this->trans('user.configureFields.lastLogin'))
        ;

        if (in_array($pageName, [Crud::PAGE_INDEX]))
        {
            return [$email, $firstName, $phone, $lastLogin];
        }
        else if (in_array($pageName, [Crud::PAGE_NEW, Crud::PAGE_EDIT, Crud::PAGE_DETAIL]))
        {
            if(Crud::PAGE_NEW === $pageName)
            {
                $password->setRequired(true);
            }

            return [
                        $panelInfo,
                        $email,
                        $firstName,
                        $phone,
                        $panelAccess,
                        $password,
                        $roles,
                        $active
                    ];
        }

        return [];
    }

    public function updateEntity (EntityManagerInterface $entityManager, $entityInstance): void
    {
        if ($entityInstance->getPlainPassword())
        {
            $entityInstance->setPassword($this->userPasswordHasher->hashPassword($entityInstance, $entityInstance->getPlainPassword()));
        }

        if (empty($entityInstance->getRoles()))
        {
            $entityInstance->addRole(User::ROLE_USER);
        }

        parent::updateEntity($entityManager, $entityInstance);
    }


    public function persistEntity (EntityManagerInterface $entityManager, $entityInstance): void
    {
        if ($entityInstance->getPlainPassword())
        {
            $entityInstance->setPassword($this->userPasswordHasher->hashPassword($entityInstance, $entityInstance->getPlainPassword()));
        }

        if (empty($entityInstance->getRoles()))
        {
            $entityInstance->addRole(User::ROLE_USER);
        }

        parent::persistEntity($entityManager, $entityInstance);
    }


    public function impersonate (AdminContext $context)
    {
        /**
         * @var User $user
         */
        $user = $this->context->getContext()->getEntity()->getInstance();

        $length          = 40;
        $impersonateCode = substr(bin2hex(random_bytes($length)), 0, $length);

        $user->setImpersonateCode($impersonateCode);
        $this->em->flush();

        return $this->redirect('/user/impersonate/' . $impersonateCode);
    }
}
