<?php

/**
 * Copyright distrib (2018)
 *
 * contact@opendistrib.net
 *
 * Ce logiciel est un programme informatique servant à aider les producteurs
 * à distribuer leur production en circuits courts.
 *
 * Ce logiciel est régi par la licence CeCILL soumise au droit français et
 * respectant les principes de diffusion des logiciels libres. Vous pouvez
 * utiliser, modifier et/ou redistribuer ce programme sous les conditions
 * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
 * sur le site "http://www.cecill.info".
 *
 * En contrepartie de l'accessibilité au code source et des droits de copie,
 * de modification et de redistribution accordés par cette licence, il n'est
 * offert aux utilisateurs qu'une garantie limitée.  Pour les mêmes raisons,
 * seule une responsabilité restreinte pèse sur l'auteur du programme,  le
 * titulaire des droits patrimoniaux et les concédants successifs.
 *
 * A cet égard  l'attention de l'utilisateur est attirée sur les risques
 * associés au chargement,  à l'utilisation,  à la modification et/ou au
 * développement et à la reproduction du logiciel par l'utilisateur étant
 * donné sa spécificité de logiciel libre, qui peut le rendre complexe à
 * manipuler et qui le réserve donc à des développeurs et des professionnels
 * avertis possédant  des  connaissances  informatiques approfondies.  Les
 * utilisateurs sont donc invités à charger  et  tester  l'adéquation  du
 * logiciel à leurs besoins dans des conditions permettant d'assurer la
 * sécurité de leurs systèmes et ou de leurs données et, plus généralement,
 * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.
 *
 * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
 * pris connaissance de la licence CeCILL, et que vous en avez accepté les
 * termes.
 */

namespace backend\controllers;

use backend\models\CreditForm;
use common\helpers\GlobalParam;
use backend\models\MailForm;
use common\helpers\Password;
use common\logic\Order\Order\Model\OrderSearch;
use common\logic\PointSale\PointSale\Model\PointSale;
use common\logic\PointSale\UserPointSale\Model\UserPointSale;
use common\logic\User\User\Model\User;
use common\logic\User\User\Model\UserSearch;
use common\logic\User\UserProducer\Model\UserProducer;
use common\logic\User\UserUserGroup\Model\UserUserGroup;
use yii\base\UserException;
use yii\filters\AccessControl;
use \Yii;
use yii\helpers\Html;
use yii\web\NotFoundHttpException;

/**
 * UserController implements the CRUD actions for User model.
 */
class UserController extends BackendController
{
    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::class,
                'rules' => [
                    [
                        'allow' => true,
                        'roles' => ['@'],
                        'matchCallback' => function ($rule, $action) {
                            return $this->getUserModule()
                                ->getAuthorizationChecker()
                                ->isGrantedAsProducer($this->getUserCurrent());
                        }
                    ]
                ],
            ],
        ];
    }

    /**
     * Liste les utilisateurs.
     */
    public function actionIndex(
        int  $idPointSale = 0,
        bool $sectionSubscribers = false,
        bool $sectionInactiveUsers = false)
    {
        $pointSaleModule = $this->getPointSaleModule();

        $searchModel = new UserSearch();
        $dataProvider = $searchModel->search([
            'UserSearch' => array_merge(
                [
                    'id_point_sale' => $idPointSale,
                    'inactive' => (int)$sectionInactiveUsers,
                    'subscribers' => (int)$sectionSubscribers
                ],
                isset(\Yii::$app->request->queryParams['UserSearch']) ?
                    Yii::$app->request->queryParams['UserSearch'] :
                    []
            )
        ]);

        $producer = $this->getProducerCurrent();
        $pointsSaleArray = $pointSaleModule->findPointSales();

        return $this->render('index', [
            'searchModel' => $searchModel,
            'dataProvider' => $dataProvider,
            'producer' => $producer,
            'idPointSaleActive' => $idPointSale,
            'pointsSaleArray' => $pointsSaleArray,
            'sectionInactiveUsers' => $sectionInactiveUsers,
            'sectionSubscribers' => $sectionSubscribers,
        ]);
    }

    public function actionCreate()
    {
        $userModule = $this->getUserModule();
        $producerModule = $this->getProducerModule();
        $producerCurrent = $this->getProducerCurrent();
        $model = $userModule->instanciateUser();
        $posts = Yii::$app->request->post();
        $userExist = false;

        if ($posts && isset($posts['User']['email']) && strlen($posts['User']['email']) > 0) {
            $userExist = $userModule->findOneUserByEmail($posts['User']['email']);
        }

        if ($userExist) {
            $producerModule->addUser($userExist, $producerCurrent);
            $this->processLinkPointSale($userExist);
            $this->processLinkUserGroup($userExist);
            $this->setFlash('success', "L'utilisateur que vous souhaitez créer possède déjà un compte sur la plateforme. Il vient d'être lié à votre établissement.");
        } else {
            if ($model->load(\Yii::$app->request->post()) && $model->validate() && YII_ENV != 'demo') {

                $userCreate = $userModule->getBuilder()->createUser(
                    $model->type,
                    $model->email,
                    $model->name,
                    $model->lastname,
                    $model->name_legal_person,
                    $model->phone,
                    $model->address,
                    $model->newsletter,
                    Password::generate(),
                    (bool)$model->send_mail_welcome
                );
                $userCreate->points_sale = $model->points_sale;
                $userCreate->user_groups = $model->user_groups;

                $this->processLinkPointSale($userCreate);
                $this->processLinkUserGroup($userCreate);
                //$this->processProductPricePercent($model);

                $this->setFlash('success', 'Utilisateur créé.');

                return $this->refresh();
            }
        }

        return $this->render('create', array_merge($this->initForm($model), [
            'model' => $model,
        ]));

    }

    public function actionUpdate($id)
    {
        $userModule = $this->getUserModule();
        $pointSaleModule = $this->getPointSaleModule();

        $model = $this->findModel($id);
        $previousMail = $model->email;
        $userBelongToProducer = UserProducer::findOne(['id_user' => $id, 'id_producer' => GlobalParam::getCurrentProducerId()]);
        if ($userBelongToProducer) {
            $model->newsletter = $userBelongToProducer->newsletter;
            if ($model->load(\Yii::$app->request->post()) && $model->save()) {

                // on envoie le mail de bienvenue si le mail vient d'être défini
                if (!strlen($previousMail) && strlen($model->email) && $model->send_mail_welcome) {
                    $password = Password::generate();
                    $userModule->setPassword($model, $password);
                    $model->username = $model->email;
                    $userModule->sendMailWelcome($model, $password);
                }
                $this->processLinkPointSale($model);
                $this->processLinkUserGroup($model);
                //$this->processProductPricePercent($model);

                if ($model->newsletter) {
                    $userModule->getNewsletterManager()->subscribeUserNewsletter($model);
                } else {
                    $userModule->getNewsletterManager()->unsubscribeUserNewsletter($model);
                }

                $this->setFlash('success', 'Utilisateur <strong>' . Html::encode($userModule->getUsername($model)) . '</strong> modifié.');
                return $this->redirect(['index']);
            }

            // Email de bienvenue
            $mailWelcome = Yii::$app->request->post('submit_mail_welcome');
            if ($mailWelcome) {
                $this->getUserModule()->getManager()->welcome($model);
                $this->setFlash('success', 'Email de bienvenue envoyé à <strong>' . Html::encode($userModule->getSolver()->getUsername($model)) . '</strong>.');
                return $this->redirect(['update', 'id' => $model->id]);
            }

            // Mot de passe oublié
            $newPassword = Yii::$app->request->post('submit_new_password');
            if ($newPassword) {
                $this->getUserModule()->getManager()->newPassword($model);
                $this->setFlash('success', 'Nouveau mot de passe envoyé à <strong>' . Html::encode($userModule->getSolver()->getUsername($model)) . '</strong>.');
                return $this->redirect(['update', 'id' => $model->id]);
            }
        } else {
            throw new UserException("Vous ne pouvez pas modifier cet utilisateur.");
        }

        return $this->render('update', array_merge($this->initForm($model), [
            'model' => $model,
            'pointSaleBillingArray' => $pointSaleModule->findByBillingUser($model)
        ]));
    }

    public function initForm($model)
    {
        $userPointSaleModule = $this->getUserPointSaleModule();
        $userUserGroupModule = $this->getUserUserGroupModule();
        $userProducerModule = $this->getUserProducerModule();
        $userGroupModule = $this->getUserGroupModule();

        if ($model->id) {
            $userPointSaleArray = $userPointSaleModule->findUserPointSalesByUser($model);
            if ($userPointSaleArray && count($userPointSaleArray) > 0) {
                foreach ($userPointSaleArray as $userPointSale) {
                    $model->points_sale[] = $userPointSale->id_point_sale;
                }
            }

            $userUserGroupsArray = $userUserGroupModule->findUserUserGroupsByUser($model);
            if ($userUserGroupsArray && count($userUserGroupsArray) > 0) {
                foreach ($userUserGroupsArray as $userUserGroup) {
                    $model->user_groups[] = $userUserGroup->id_user_group;
                }
            }
            $userProducer = $userProducerModule->findOneUserProducer($model);
            $model->product_price_percent = $userProducer->product_price_percent;
        }

        $pointsSaleArray = PointSale::find()
            ->where([
                'id_producer' => GlobalParam::getCurrentProducerId(),
                'status' => 1
            ])
            ->joinWith(['userPointSale' => function ($query) use ($model) {
                if ($model->id) {
                    $query->andOnCondition('user_point_sale.id_user = ' . $model->id);
                }
            }])
            ->all();

        $userGroupsArray = $userGroupModule->findUserGroups();

        return [
            'pointsSaleArray' => $pointsSaleArray,
            'userGroupsArray' => $userGroupsArray,
        ];
    }

    /**
     * Lie un utilisateur aux points de vente sélectionnés.
     */
    public function processLinkPointSale(User $modelUser)
    {
        $posts = Yii::$app->request->post();
        $userPointSaleModule = $this->getUserPointSaleModule();
        $pointSaleModule = $this->getPointSaleModule();

        UserPointSale::deleteAll([
            'id_user' => $modelUser->id
        ]);
        if (is_array($modelUser->points_sale) && count($modelUser->points_sale) > 0) {
            foreach ($modelUser->points_sale as $pointSaleId) {
                $pointSale = $pointSaleModule->findOnePointSaleById($pointSaleId);
                $userPointSale = $userPointSaleModule->findOneUserPointSale($modelUser, $pointSale);

                if (!$userPointSale) {
                    $userPointSale = new UserPointSale;
                    $userPointSale->id_user = $modelUser->id;
                    $userPointSale->id_point_sale = $pointSaleId;
                    $userPointSale->comment = isset($posts['User']['comment_point_sale_' . $pointSaleId]) ? $posts['User']['comment_point_sale_' . $pointSaleId] : '';
                    $userPointSale->save();
                }
            }
        }
    }

    /**
     * Lie un utilisateur aux groupes d'utilisateurs sélectionnés.
     */
    public function processLinkUserGroup($modelUser)
    {
        UserUserGroup::deleteAll([
            'id_user' => $modelUser->id
        ]);

        if (is_array($modelUser->user_groups) && count($modelUser->user_groups) > 0) {
            foreach ($modelUser->user_groups as $userGroupId) {

                $userUserGroup = UserUserGroup::searchOne([
                    'id_user' => $modelUser->id,
                    'id_user_group' => $userGroupId
                ]);

                if (!$userUserGroup) {
                    $userUserGroup = new UserUserGroup();
                    $userUserGroup->id_user = $modelUser->id;
                    $userUserGroup->id_user_group = $userGroupId;
                    $userUserGroup->save();
                }
            }
        }
    }

    public function processProductPricePercent($model)
    {
        $userProducer = UserProducer::searchOne([
            'id_producer' => GlobalParam::getCurrentProducerId(),
            'id_user' => $model->id
        ]);
        $userProducer->product_price_percent = $model->product_price_percent;

        $userProducer->save();
    }

    /**
     * Désactive l'utilisateur de l'établissement.
     */
    public function actionDelete(int $id)
    {
        $userModule = $this->getUserModule();
        $userProducerModule = $this->getUserProducerModule();

        $user = $userModule->findOneUserById($id);
        $userProducer = $userProducerModule->findOneUserProducer($user);

        if ($userProducer) {
            if ($userProducerModule->hasOutstandingCredit($userProducer)) {
                $this->setFlash('error', "Vous ne pouvez pas supprimer cet utilisateur car il a toujours du crédit en cours.");
            } else {
                $userProducerModule->unlinkUserProducer($userProducer);
                $this->setFlash('success', 'L\'utilisateur a bien été supprimé de votre établissement.');
            }
        } else {
            throw new \yii\web\NotFoundHttpException('L\'enregistrement UserProducer est introuvable', 404);
        }

        $params = Yii::$app->getRequest()->getQueryParams();
        unset($params['id']);

        $this->redirect(array_merge(['index'], $params));
    }

    /**
     * Affiche les données liées au crédit d'un utilisateur (formulaire, historique).
     */
    public function actionCredit(int $id)
    {
        $producerModule = $this->getProducerModule();
        $userModule = $this->getUserModule();
        $paymentModule = $this->getPaymentModule();
        $userProducerModule = $this->getUserProducerModule();

        $user = $userModule->findOneUserById($id);
        $userProducer = $userProducerModule->getRepository()->findOneUserProducer($user);

        if ($userProducer) {
            $creditForm = new CreditForm();
            $creditForm->send_mail = $producerModule->getSolver()->getConfig('option_check_by_default_prevent_user_credit');

            if ($creditForm->load(\Yii::$app->request->post()) && $creditForm->validate()) {

                $paymentModule->getManager()
                    ->creditOrDebitUser(
                        $creditForm->type,
                        $user,
                        $creditForm->amount,
                        $creditForm->mean_payment,
                        $this->getUserCurrent(),
                        $creditForm->comment
                    );

                if ($creditForm->send_mail) {
                    $paymentModule->getNotifier()
                        ->notifyUserCreditMovement(
                            $user,
                            $creditForm->type,
                            $creditForm->amount
                        );
                    if (!$user->email) {
                        $this->addFlash('error', "L'utilisateur n'a pas pu être prévenu car son adresse email n'est pas définie.");
                    }
                }

                $this->addFlash('success', 'Crédit mis à jour.');

                return $this->refresh();
            }

            return $this->render('credit', [
                'user' => $user,
                'userProducer' => $userProducer,
                'creditForm' => $creditForm,
                'dataProvider' => $paymentModule->getRepository()
                    ->queryPaymentsCreditHistoryByUser($user)->getDataProvider(20),
            ]);
        } else {
            throw new UserException("Utilisateur introuvable.");
        }
    }

    /**
     * Modifie l'option "credit_active" d'un utilisateur pour le producteur courant.
     * Redirige vers la page de crédit de l'utilisateur.
     */
    public function actionStateCredit($idUser, $state)
    {
        $userModule = $this->getUserModule();
        $userProducerModule = $this->getUserProducerModule();

        $user = $userModule->findOneUserById($idUser);
        $userProducer = $userProducerModule->findOneUserProducer($user);

        if ($userProducer) {
            $userProducer->credit_active = $state;
            $userProducer->save();
        }

        return $this->redirect(['user/credit', 'id' => $idUser]);
    }

    /**
     * Affiche les commandes d'un utilisateur.
     *
     * @param integer $id
     * @return mixed
     */
    public function actionOrders($id)
    {
        $userModule = $this->getUserModule();

        $user = $userModule->findOneUserById($id);
        $searchModel = new OrderSearch();
        $dataProvider = $searchModel->search(array_merge(\Yii::$app->request->queryParams, ['id_user' => $id]));

        return $this->render('orders', [
            'user' => $user,
            'searchModel' => $searchModel,
            'dataProvider' => $dataProvider,
        ]);
    }

    /**
     * Finds the User model based on its primary key value.
     * If the model is not found, a 404 HTTP exception will be thrown.
     */
    protected function findModel($id)
    {
        $userModule = $this->getUserModule();

        if (($user = $userModule->findOneUserById($id)) !== null) {
            return $user;
        } else {
            throw new NotFoundHttpException("Utilisateur introuvable");
        }
    }

    /**
     * Affiche la liste des emails des utilisateurs liés à un point de vente donné.
     */
    public function actionMail(
        $idPointSale = 0,
        $sectionSubscribers = 0,
        $sectionInactiveUsers = 0,
        $usersPointSaleLink = 0,
        $usersPointSaleHasOrder = 0)
    {
        $userModule = $this->getUserModule();
        $distributionModule = $this->getDistributionModule();

        if ($idPointSale && !$usersPointSaleLink && !$usersPointSaleHasOrder) {
            $usersPointSaleLink = 1;
        }

        $users = $userModule->queryUsersBy([
            'id_producer' => GlobalParam::getCurrentProducerId(),
            'id_point_sale' => $idPointSale,
            'users_point_sale_link' => $usersPointSaleLink,
            'users_point_sale_has_order' => $usersPointSaleHasOrder,
            'subscribers' => $sectionSubscribers,
            'inactive' => $sectionInactiveUsers,
            'newsletter' => true
        ])->all();

        $usersArray = [];
        foreach ($users as $key => $user) {
            if (isset($user['email']) && strlen($user['email']) > 0) {
                $usersArray[] = $user['email'];
            } else {
                unset($users[$key]);
            }
        }

        $pointsSaleArray = PointSale::find()->where(['id_producer' => GlobalParam::getCurrentProducerId(), 'status' => 1])->all();

        $pointSale = null;
        if ($idPointSale) {
            $pointSale = PointSale::findOne(['id' => $idPointSale]);
        }

        $mailForm = new MailForm();
        if ($mailForm->load(\Yii::$app->request->post()) && $mailForm->validate()) {
            $responseSendMail = $mailForm->sendEmail($users);
            if ($responseSendMail->success()) {
                $this->setFlash('success', 'Votre email a bien été envoyé.');
            } else {
                $bodyResponseSendMail = $responseSendMail->getBody();
                $emailsErrorArray = [];

                if (isset($bodyResponseSendMail['Messages'])) {
                    foreach ($bodyResponseSendMail['Messages'] as $message) {
                        if ($message['Status'] != 'success') {
                            $emailsErrorArray[] = $message['Errors'][0]['ErrorMessage'];
                        }
                    }
                }

                $messageError = 'Un problème est survenu lors de l\'envoi de votre email.';
                if (count($emailsErrorArray) > 0) {
                    $messageError .= '<br />Problème détecté : ' . implode(',', $emailsErrorArray);
                }
                $this->setFlash('error', $messageError);
            }

            return $this->redirect(['mail', 'idPointSale' => $idPointSale]);
        }

        $incomingDistributions = $distributionModule->findDistributionsIncoming();
        $incomingDistributionsArray = ['0' => '--'];
        foreach ($incomingDistributions as $distribution) {
            $incomingDistributionsArray[$distribution->id] = strftime('%A %d %B %Y', strtotime($distribution->date));
        }

        return $this->render('emails', [
            'usersArray' => $usersArray,
            'pointsSaleArray' => $pointsSaleArray,
            'pointSale' => $pointSale,
            'mailForm' => $mailForm,
            'idPointSaleActive' => $idPointSale,
            'incomingDistributionsArray' => $incomingDistributionsArray,
            'sectionSubscribers' => $sectionSubscribers,
            'sectionInactiveUsers' => $sectionInactiveUsers,
            'usersPointSaleLink' => $usersPointSaleLink,
            'usersPointSaleHasOrder' => $usersPointSaleHasOrder,
        ]);
    }

    public function actionSwitchIdentity(int $id)
    {
        $userModule = $this->getUserModule();
        if ($this->isUserCurrentAdmin()) {
            $initialId = Yii::$app->user->getId();
            if ($initialId != $id) {
                $user = $userModule->findOneUserById($id);
                $duration = 0;
                Yii::$app->user->switchIdentity($user, $duration);
                Yii::$app->session->set('user.idbeforeswitch', $initialId);
                return $this->redirect(['index']);
            }
        } else {
            throw new NotFoundHttpException('Page introuvable');
        }
    }
}
