<?php

namespace domain\User\User;

use domain\Payment\Payment;
use domain\Producer\Producer\ProducerSolver;
use domain\User\UserGroup\UserGroup;
use domain\User\UserProducer\UserProducer;
use domain\User\UserUserGroup\UserUserGroup;
use domain\_\AbstractService;
use domain\_\SolverInterface;
use Faker\Factory;
use yii\base\ErrorException;

class UserSolver extends AbstractService implements SolverInterface
{
    public function getTypeChoicesArray(): array
    {
        return [
            User::TYPE_INDIVIDUAL => 'Particulier',
            User::TYPE_LEGAL_PERSON => 'Personne morale',
            User::TYPE_GUEST => 'Visiteur'
        ];
    }

    public function getTypeLabel(string $type): string
    {
        $typesArray = $this->getTypeChoicesArray();
        if(key_exists($type, $typesArray)) {
            return $typesArray[$type];
        }

        return '';
    }

    public function getTypeIndex(string $typeLabel = null): ?string
    {
        foreach($this->getTypeChoicesArray() as $key => $label) {
            if($label == $typeLabel) {
                return $key;
            }
        }

        return null;
    }

    public function isTypeValid(string $type = null): bool
    {
        return in_array($type, User::$types);
    }

    public function isTypeLegalPerson(User $user): bool
    {
        return $user->type == User::TYPE_LEGAL_PERSON;
    }

    public function isTypeIndividual(User $user): bool
    {
        return $user->type == User::TYPE_INDIVIDUAL;
    }

    public function isTypeGuest(User $user): bool
    {
        return $user->type == User::TYPE_GUEST;
    }

    public function getContactSummaryFromArrayAsHtml(array $user): string
    {
        $html = '';

        if (strlen($user['phone'])) {
            $html .= $user['phone'];
        }

        if (strlen($user['phone']) && strlen($user['email'])) {
            $html .= '<br />';
        }

        if (strlen($user['email'])) {
            $html .= $user['email'];
        }

        return $html;
    }

    // getStrUserAction
    public function getPaymentUsernameUserAction(Payment $payment): string
    {
        $userAction = $payment->getUserActionObject();

        if ($userAction) {
            return $this->getUsername($userAction);
        } else {
            return 'Système';
        }
    }

    public function getPhone(User $user)
    {
        if($this->getProducerContext() && $this->getProducerContext()->isDemoAccount()) {
            return \Yii::$app->faker->phoneNumber();
        }

        return $user->phone;
    }

    public function getEmail(User $user)
    {
        if($this->getProducerContext() && $this->getProducerContext()->isDemoAccount()) {
            return \Yii::$app->faker->email();
        }

        return $user->email;
    }

    public function getAddress(User $user): string
    {
        if($this->getProducerContext() && $this->getProducerContext()->isDemoAccount()) {
            return \Yii::$app->faker->address();
        }

        return $user->address;
    }

    /**
     * @throws ErrorException
     */
    public function getUsername(User $user, $withType = false): string
    {
        if($this->getProducerContext() && $this->getProducerContext()->isDemoAccount()) {
            $username = \Yii::$app->faker->name();
        }
        else {
            if ($this->isTypeLegalPerson($user)
                && isset($user->name_legal_person)
                && strlen($user->name_legal_person)) {

                $username = $user->name_legal_person;
            } else {
                $username = $user->lastname . ' ' . $user->name;
            }
        }

        if ($withType && $this->isTypeLegalPerson($user)) {
            $username = $username . ' (personne morale)';
        }

        return $username;
    }

    public function getUsernameFromArray(array $modelArray, $withType = false): string
    {
        if($this->getProducerContext() && $this->getProducerContext()->isDemoAccount()) {
            $username = \Yii::$app->faker->name();
        }
        else {
            $username = 'Nom indéfini';
            if ($modelArray['type'] == User::TYPE_LEGAL_PERSON
                && isset($modelArray['name_legal_person'])
                && strlen($modelArray['name_legal_person'])) {
                $username = $modelArray['name_legal_person'];
            } elseif((isset($modelArray['lastname']) && $modelArray['lastname'])
                || (isset($modelArray['name']) && $modelArray['name'])) {
                $username = $modelArray['lastname'] . ' ' . $modelArray['name'];
            }
        }

        if ($withType && $modelArray['type'] == User::TYPE_LEGAL_PERSON) {
            $username = $username . ' (personne morale)';
        }

        return $username;
    }

    public function getFullAddress(User $user, $nl2br = false)
    {
        $address = '';
        if (isset($user->lastname) && isset($user->name) && strlen($user->lastname) && strlen($user->name)) {
            $address .= $user->lastname . ' ' . $user->name . "\n";
        }
        if (isset($user->name_legal_person) && strlen($user->name_legal_person)) {
            $address .= $user->name_legal_person . "\n";
        }
        $address .= $user->address;

        if ($nl2br) {
            $address = nl2br($address);
        }

        return $address;
    }

    /**
     * Finds out if password reset token is valid
     *
     * @param string $token password reset token
     * @return boolean
     */
    public function isPasswordResetTokenValid($token)
    {
        if (empty($token)) {
            return false;
        }
        $expire = \Yii::$app->parameterBag->get('user.passwordResetTokenExpire');
        $parts = explode('_', $token);
        $timestamp = (int)end($parts);
        return $timestamp + $expire >= time();
    }

    /**
     * Retourne si l'utilisateur est un admin ou non.
     *
     */
    public function isAdmin(User $user): bool
    {
        return $user->status == User::STATUS_ADMIN;
    }

    public function isStatusAdministrator(User $user): bool
    {
        return $user->getStatus() == User::STATUS_ADMIN;
    }

    /**
     * Retourne si l'utilisateur est un producteur ou non.
     *
     */
    public function isProducer(User $user): bool
    {
        return ($user->status == User::STATUS_ADMIN
                || $user->status == User::STATUS_PRODUCER) && $user->id_producer;
    }

    public function isStatusProducer(User $user): bool
    {
        return $user->getStatus() == User::STATUS_PRODUCER;
    }

    public function isStatusUser(User $user): bool
    {
        return $user->getStatus() == User::STATUS_ACTIVE;
    }

    /**
     * Retourne l'utilisateur courant.
     *
     */
    public function getCurrent(): ?User
    {
        if (!\Yii::$app->user->isGuest) {
            return \Yii::$app->user->identity;
        }

        return null;
    }

    public function isCurrentGuest(): bool
    {
        return \Yii::$app->user->isGuest;
    }

    /**
     * Retourne si l'utilisateur courant est connecté ou non.
     *
     */
    public function isCurrentConnected(): bool
    {
        return !\Yii::$app->user->isGuest;
    }

    /**
     * Retourne l'ID de l'utilisateur courant connecté.
     *
     */
    public function getCurrentId()
    {
        if (!\Yii::$app->user->isGuest) {
            return \Yii::$app->user->identity->id;
        }

        return false;
    }

    /**
     * Retourne le status de l'utilisateur courant connecté.
     *
     */
    public function getCurrentStatus()
    {
        if (!\Yii::$app->user->isGuest) {
            return \Yii::$app->user->identity->status;
        }

        return false;
    }

    public function hasAccessBackend(): bool
    {
        $userCurrentStatus = $this->getCurrentStatus();

        return $userCurrentStatus == User::STATUS_ADMIN
            || $userCurrentStatus == User::STATUS_PRODUCER;
    }

    // belongsToUserGroup
    public function isUserBelongsToUserGroup(User $user, UserGroup $userGroup): bool
    {
        if (!$user->userUserGroup) {
            $user->populateRelation('userUserGroup', UserUserGroup::searchAll([
                'id_user' => $user->id
            ]));
        }

        if ($user->userUserGroup) {
            foreach ($user->userUserGroup as $userUserGroup) {
                if ($userUserGroup->id_user_group == $userGroup->id) {
                    return true;
                }
            }
        }

        return false;
    }

    public function getUserProducer(User $user): ?UserProducer
    {
        $userProducer = null;
        $producerId = $this->getProducerContextId();
        foreach($user->userProducer as $userProducerRelation) {
            if($userProducerRelation->id_producer == $producerId) {
                $userProducer = $userProducerRelation;
            }
        }
        return $userProducer;
    }

    public function getEmailSendingInvoicingDocuments(User $user): ?string
    {
        if($user->email_sending_invoicing_documents && strlen($user->email_sending_invoicing_documents) > 0) {
            return $user->email_sending_invoicing_documents;
        }

        if($user->email && strlen($user->email) > 0) {
            return $user->email;
        }

        return null;
    }
}