<?php

namespace domain\User\User;

use common\helpers\Password;
use domain\Producer\Producer\Producer;
use domain\User\User\Event\UserCreateEvent;
use domain\User\UserGroup\UserGroup;
use domain\User\UserProducer\UserProducerBuilder;
use domain\User\UserUserGroup\UserUserGroupBuilder;
use domain\_\AbstractBuilder;

class UserBuilder extends AbstractBuilder
{
    protected UserRepository $userRepository;
    protected UserNotifier $userNotifier;
    protected UserProducerBuilder $userProducerBuilder;
    protected UserUserGroupBuilder $userUserGroupBuilder;

    public function loadDependencies(): void
    {
        $this->userRepository = $this->loadService(UserRepository::class);
        $this->userNotifier = $this->loadService(UserNotifier::class);
        $this->userProducerBuilder = $this->loadService(UserProducerBuilder::class);
        $this->userUserGroupBuilder = $this->loadService(UserUserGroupBuilder::class);
    }

    public function instanciateUser(
        string $type = null,
        string $email = null,
        string $firstname = null,
        string $lastname = null,
        string $nameLegalPerson = null,
        string $phone = null,
        string $address = null,
        string $password = null
    ): User
    {
        $user = new User();
        $user->id_producer = 0;
        $user->type = $type;
        $this->initUsername($user, $email);
        $user->email = $email;
        $user->name = $firstname;
        $user->lastname = $lastname;
        $user->name_legal_person = $nameLegalPerson;
        $user->phone = $phone;
        $user->address = $address;
        $this->initPassword($user, $password);

        return $user;
    }

    public function createUser(
        string $type = null,
        string $email = null,
        string $firstname = null,
        string $lastname = null,
        string $nameLegalPerson = null,
        string $phone = null,
        string $address = null,
        bool $newsletter = true,
        string $password = null,
        bool $sendMailWelcome = true
    ): User
    {
        $userExist = null;
        if($email && strlen($email)) {
            $userExist = $this->userRepository->findOneUserByEmail($email);
            $user = $userExist;
        }

        if(!$userExist) {
            $user = $this->instanciateUser(
                $type,
                $email,
                $firstname,
                $lastname,
                $nameLegalPerson,
                $phone,
                $address,
                $password
            );
            $this->create($user);

            if($sendMailWelcome) {
                $this->userNotifier->sendMailWelcome($user, $password);
            }
        }

        $user->triggerEvent(
            UserCreateEvent::class,
            [
                'user' => $user,
                'producer' => $this->getProducerContext(),
                'newsletter' => $newsletter
            ]
        );

        return $user;
    }

    public function initUsername(User $user, string $email = null)
    {
        $user->username = $email;
        if (!$email) {
            $user->username = 'inconnu@souke.fr';
        }
    }

    public function initPassword(User $user, string $password = null)
    {
        if(!$password) {
            $password = Password::generate();
        }
        $this->setPassword($user, $password);
        $this->generateAuthKey($user);
    }

    /**
     * Generates password hash from password and sets it to the model
     */
    public function setPassword(User $user, string $password): void
    {
        $user->password_hash = \Yii::$app->security->generatePasswordHash($password);
    }

    public function generatePassword(User $user): string
    {
        $password = Password::generate();
        $this->setPassword($user, $password);
        $this->update($user);
        return $password;
    }

    /**
     * Generates "remember me" authentication key
     */
    public function generateAuthKey(User $user): void
    {
        $user->auth_key = \Yii::$app->security->generateRandomString();
    }

    public function initProducer(User $user, Producer $producer)
    {
        $user->id_producer = $producer->id;
        $user->status = User::STATUS_PRODUCER;
    }

    /**
     * Met à jour la date de dernière connexion de l'utilisateur.
     */
    public function updateUserLastConnection(User $user)
    {
        $user->date_last_connection = date('Y-m-d H:i:s');
        $user->save();
    }

    /**
     * Generates new password reset token
     */
    public function generatePasswordResetToken(User $user): void
    {
        $user->password_reset_token = \Yii::$app->security->generateRandomString() . '_' . time();
    }

    /**
     * Removes password reset token
     */
    public function removePasswordResetToken(User $user)
    {
        $user->password_reset_token = null;
    }

    public function grantAccess(User $user): bool
    {
        if($this->userRepository->isActive($user)) {
            $user->id_producer = $this->getProducerContextId();
            $user->status = User::STATUS_PRODUCER;
            return $user->save();
        }

        return false;
    }

    public function deleteAccess(User $user): bool
    {
        if($this->userRepository->isActive($user)) {
            $user->id_producer = null;
            $user->status = User::STATUS_ACTIVE;
            return $user->save();
        }

        return false;
    }

    public function switchProducer(User $user, Producer $producer)
    {
        $user->id_producer = $producer->id;
        $this->update($user);
    }

    public function addUserGroup(User $user, UserGroup $userGroup)
    {
        $this->userUserGroupBuilder->createUserUserGroup($user, $userGroup);
    }
}