<?php

namespace KupShop\UserBundle\Security;

use Query\Operator;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;

class UserProvider implements UserProviderInterface
{
    use \DatabaseCommunication;

    /** @var TokenStorageInterface */
    private $tokenStorage;

    /** @var SessionInterface */
    private $session;

    public function __construct(TokenStorageInterface $tokenStorage, SessionInterface $session)
    {
        $this->tokenStorage = $tokenStorage;
        $this->session = $session;
    }

    /**
     * Loads the user for the given username.
     *
     * This method must throw UsernameNotFoundException if the user is not
     * found.
     *
     * @param string $username The username
     *
     * @return User
     *
     * @throws UsernameNotFoundException if the user is not found
     */
    public function loadUserByUsername($username)
    {
        if (!$email = $this->getEmailByUsername($username)) {
            throw new UserNotFoundException();
        }

        $user = \User::createFromLogin($email);
        if (!isset($user)) {
            throw new UserNotFoundException();
        }

        return new User($user->id, $user->email, $user->passw, ['ROLE_USER'], $user);
    }

    public function loadUserById($id)
    {
        $user = \User::createFromId($id);
        if (!isset($user)) {
            throw new UserNotFoundException();
        }

        return new User($user->id, $user->email, $user->passw, ['ROLE_USER'], $user);
    }

    /**
     * Refreshes the user for the account interface.
     *
     * It is up to the implementation to decide if the user data should be
     * totally reloaded (e.g. from the database), or if the UserInterface
     * object can just be merged into some internal array of users / identity
     * map.
     *
     * @throws UnsupportedUserException if the account is not supported
     */
    public function refreshUser(UserInterface $user): UserInterface
    {
        if ($user instanceof User) {
            $user = $this->loadUserByUsername($user->getUsername());

            $user->getKupshopUser()->activateUser();

            return $user;
        }

        throw new UnsupportedUserException();
    }

    /**
     * Whether this provider supports the given user class.
     *
     * @param string $class
     */
    public function supportsClass($class): bool
    {
        return $class === User::class;
    }

    public function loadUserByIdentifier(string $identifier): UserInterface
    {
        return $this->loadUserByUsername($identifier);
    }

    protected function getEmailByUsername(string $username): ?string
    {
        if (str_contains($username, '@')) {
            return $username;
        }

        $email = sqlQueryBuilder()
            ->select('email')
            ->from('users')
            ->where(Operator::equals(['phone' => $username]))
            ->execute()->fetchOne();

        return $email ?: null;
    }
}
