<?php

namespace AutoAdmin\Bundle\Admin\Service;

use AutoAdmin\Bundle\Admin\Factory\ContentFactory;
use AutoAdmin\Bundle\Admin\Model\AdministratorInterface;
use AutoAdmin\Bundle\Core\Doctrine\DoctrineInterfaceAliasResolver;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Exception\ORMException;
use Doctrine\ORM\OptimisticLockException;
use Exception;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;

class AdministratorManager
{
    public function __construct(
        protected EntityManagerInterface $em,
        protected UserPasswordHasherInterface $hasher,
        protected ContentFactory $contentFactory,
    ) {
    }

    /**
     * @throws Exception
     */
    public function create(
        string $username,
        string $email,
        string $plainPassword,
        array $roles,
        bool $enabled = false
    ): AdministratorInterface {
        if ($this->checkAlreadyExist($username, $email)) {
            throw new Exception("The user has not been created. Email or username already exist for admin.");
        }

        $admin = $this->contentFactory->createEntity(AdministratorInterface::class);
        $admin->setUsername($username);
        $admin->setEmail($email);
        $admin->setRoles($roles);
        $admin->setPassword($this->hasher->hashPassword($admin, $plainPassword));
        $admin->setEnabled($enabled);

        $this->em->persist($admin);
        $this->em->flush();

        return $admin;
    }

    public function checkAlreadyExist(string $username, string $email = null): bool
    {
        $userRepo = $this->em->getRepository(AdministratorInterface::class);

        if ($userRepo->findOneBy(['username' => $username]) !== null) {
            return true;
        }

        if ($email !== null && $userRepo->findOneBy(['email' => $email]) !== null) {
            return true;
        }

        return false;
    }

    /**
     * @throws Exception
     * @throws ORMException
     * @throws OptimisticLockException
     */
    public function changePassword(string $username, string $plainPassword): AdministratorInterface
    {
        if (!$this->checkAlreadyExist($username)) {
            throw new Exception("The user was not found.");
        }

        /** @var AdministratorInterface $admin */
        $admin = $this->em->getRepository(AdministratorInterface::class)->findOneBy(['username' => $username]);
        $admin->setPassword($this->hasher->hashPassword($admin, $plainPassword));

        $this->em->persist($admin);
        $this->em->flush();

        return $admin;
    }
}
