<?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 common\helpers\GlobalParam;
use common\models\User;
use common\models\Producer;
use common\models\Distribution;
use backend\models\MailForm;
use common\models\UserGroup;
use common\models\UserProducer;
use common\models\UserPointSale;
use common\models\PointSale;
use common\models\UserUserGroup;

/**
 * UserController implements the CRUD actions for User model.
 */
class UserController extends BackendController
{

        public function behaviors()
        {
                return [
                        'verbs' => [
                                'class' => VerbFilter::className(),
                                'actions' => [
                                ],
                        ],
                        'access' => [
                                'class' => AccessControl::className(),
                                'rules' => [
                                        [
                                                'allow' => true,
                                                'roles' => ['@'],
                                                'matchCallback' => function ($rule, $action) {
                                                        return User::hasAccessBackend();
                                                }
                                        ]
                                ],
                        ],
                ];
        }

        /**
         * Liste les utilisateurs.
         *
         * @return mixed
         */
        public function actionIndex(
                $idPointSale = 0, $sectionSubscribers = false, $sectionInactiveUsers = false)
        {
                $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 = Producer::searchOne([
                        'id' => GlobalParam::getCurrentProducerId()
                ]);

                $pointsSaleArray = PointSale::searchAll();

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

        public function initForm($model)
        {

                if ($model->id) {
                        // init points de vente sélectionnés
                        $userPointSaleArray = UserPointSale::searchAll([
                                'id_user' => $model->id
                        ]);
                        if ($userPointSaleArray && count($userPointSaleArray) > 0) {
                                foreach ($userPointSaleArray as $userPointSaleArray) {
                                        $model->points_sale[] = $userPointSaleArray->id_point_sale;
                                }
                        }

                        // init groupes d'utilisateurs sélectionnés
                        $userUserGroupsArray = UserUserGroup::searchAll([
                                'id_user' => $model->id
                        ]);
                        if ($userUserGroupsArray && count($userUserGroupsArray) > 0) {
                                foreach ($userUserGroupsArray as $userUserGroup) {
                                        $model->user_groups[] = $userUserGroup->id_user_group;
                                }
                        }

                        // product price percent
                        $userProducer = UserProducer::searchOne([
                                'id_producer' => GlobalParam::getCurrentProducerId(),
                                'id_user' => $model->id
                        ]) ;
                        $model->product_price_percent = $userProducer->product_price_percent ;
                }

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

                // groupes d'utilisateurs
                $userGroupsArray = UserGroup::find()
                        ->where([
                                'id_producer' => GlobalParam::getCurrentProducerId(),
                        ])
                        ->all();

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

        /**
         * Creates a new User model.
         * If creation is successful, the browser will be redirected to the 'view' page.
         * @return mixed
         */
        public function actionCreate()
        {
                $model = new User();

                $userExist = false ;
                $posts = Yii::$app->request->post() ;

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

                if ($userExist) {
                        Producer::addUser($userExist->id, GlobalParam::getCurrentProducerId()) ;
                        $this->processLinkPointSale($userExist);
                        $this->processLinkUserGroup($userExist);
                        Yii::$app->getSession()->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') {
                                // save user
                                $password = Password::generate();
                                $model->id_producer = 0;
                                $model->setPassword($password);
                                $model->generateAuthKey();
                                $model->username = $model->email;
                                if (!strlen($model->email)) {
                                        $model->username = 'inconnu@opendistrib.net';
                                }

                                $model->save();

                                // liaison etablissement / user
                                $useProducer = new UserProducer();
                                $useProducer->id_user = $model->id;
                                $useProducer->id_producer = GlobalParam::getCurrentProducerId();
                                $useProducer->credit = 0;
                                $useProducer->active = 1;
                                $useProducer->save();

                                $model->sendMailWelcome($password);
                                $this->processLinkPointSale($model);
                                $this->processLinkUserGroup($model);
                                $this->processProductPricePercent($model) ;

                                Yii::$app->getSession()->setFlash('success', 'Utilisateur créé.');
                                $model = new User();
                        }
                }

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

        }

        /**
         * Updates an existing User model.
         * If update is successful, the browser will be redirected to the 'view' page.
         * @param integer $id
         * @return mixed
         */
        public function actionUpdate($id)
        {
                $model = $this->findModel($id);

                // Moodification du profil
                $previousMail = $model->email;
                $user = User::find()->with('userProducer')->where(['id' => $model['id']])->one();
                $userBelongToProducer = UserProducer::findOne(['id_user' => $id, 'id_producer' => GlobalParam::getCurrentProducerId()]);
                if ($userBelongToProducer) {
                        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)) {
                                        $password = Password::generate();
                                        $model->setPassword($password);
                                        $model->username = $model->email;
                                        $model->sendMailWelcome($password);
                                }
                                $this->processLinkPointSale($model);
                                $this->processLinkUserGroup($model);
                                $this->processProductPricePercent($model) ;
                                Yii::$app->getSession()->setFlash('success', 'Utilisateur modifié.');
                        }
                } else {
                        throw new UserException("Vous ne pouvez pas modifier cet utilisateur.");
                }

                // Nouveau mot de passe
                $newPassword = Yii::$app->request->post('submit_new_password');
                if ($newPassword) {
                        $password = Password::generate();
                        $model->setPassword($password);
                        $model->save();

                        $producer = GlobalParam::getCurrentProducer();
                        Yii::$app->mailer->compose();
                        $mail = Yii::$app->mailer->compose(
                                ['html' => 'newPasswordUserAdmin-html', 'text' => 'newPasswordUserAdmin-text'], ['user' => $model, 'producer' => $producer, 'password' => $password]
                        )
                                ->setTo($model->email)
                                ->setFrom(['contact@opendistrib.net' => 'Opendistrib'])
                                ->setSubject('[Opendistrib] Nouveau mot de passe')
                                ->send();
                        Yii::$app->getSession()->setFlash('success', 'Nouveau mot de passe envoyé.');
                }

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

        /**
         * Lie un utilisateur aux points de vente sélectionnés.
         *
         * @param User $modelUser
         */
        public function processLinkPointSale($modelUser)
        {
                $posts = Yii::$app->request->post();
                UserPointSale::deleteAll([
                        'id_user' => $modelUser->id
                ]);
                if (is_array($modelUser->points_sale) && count($modelUser->points_sale) > 0) {
                        foreach ($modelUser->points_sale as $pointSaleId) {
                                $userPointSale = UserPointSale::searchOne([
                                        'id_user' => $modelUser->id,
                                        'id_point_sale' => $pointSaleId
                                ]);
                                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.
         *
         * @param User $modelUser
         */
        public function processLinkUserGroup($modelUser)
        {
                $posts = Yii::$app->request->post();
                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.
         *
         * @param integer $id ID de l'utilisateur
         */
        public function actionDelete($id)
        {
                $userProducer = UserProducer::findOne([
                        'id_user' => $id,
                        'id_producer' => GlobalParam::getCurrentProducerId()
                ]);
                if ($userProducer) {
                        $userProducer->active = 0;
                        $userProducer->bookmark = 0;
                        $userProducer->save();
                        Yii::$app->getSession()->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 la liste des emails des utilisateurs liés à un point de vente
         * donné.
         *
         * @param integer $idPointSale
         * @return mixed
         */
        public function actionMail(
                $idPointSale = 0,
                $sectionSubscribers = 0,
                $sectionInactiveUsers = 0,
                $usersPointSaleLink = 0,
                $usersPointSaleHasOrder = 0)
        {
                if ($idPointSale && !$usersPointSaleLink && !$usersPointSaleHasOrder) {
                        $usersPointSaleLink = 1;
                }

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

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

                $pointsSaleArray = PointSale::find()->where(['id_producer' => GlobalParam::getCurrentProducerId()])->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()) {
                                Yii::$app->getSession()->setFlash('success', 'Votre email a bien été envoyé.');
                        } else {
                                $bodyResponseSendMail = $responseSendMail->getBody();
                                $emailsErrorArray = [];
                                foreach ($bodyResponseSendMail['Messages'] as $message) {
                                        if ($message['Status'] != 'success') {
                                                $emailsErrorArray[] = $message['To']['Email'];
                                        }
                                }
                                $messageError = 'Un problème est survenu lors de l\'envoi de votre email.';
                                if (count($emailsErrorArray) > 0) {
                                        $messageError .= '<br />Problème détecté sur les adresses suivantes : ' . implode(',', $emailsErrorArray);
                                }
                                Yii::$app->getSession()->setFlash('error', $messageError);
                        }

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

                $incomingDistributions = Distribution::getIncomingDistributions();
                $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,
                ]);
        }

        /**
         * Affiche les données liées au crédit d'un utilisateur (formulaire,
         * historique).
         *
         * @param integer $id
         * @return mixed
         * @throws UserException
         */
        public function actionCredit($id)
        {
                $user = User::find()->with('userProducer')->where(['id' => $id])->one();
                $userProducer = UserProducer::findOne(['id_user' => $id, 'id_producer' => GlobalParam::getCurrentProducerId()]);

                if (($userProducer) || User::getCurrentStatus() == User::STATUS_ADMIN) {

                        $creditForm = new CreditForm;
                        if ($creditForm->load(Yii::$app->request->post()) && $creditForm->validate()) {
                                $creditForm->id_user = $id;
                                $creditForm->save();
                                $creditForm = new CreditForm;
                        }

                        $history = CreditHistory::find()
                                ->with(['order', 'userAction'])
                                ->where([
                                        'id_user' => $user->id,
                                        'id_producer' => GlobalParam::getCurrentProducerId(),
                                ])
                                ->orderBy('date DESC')
                                ->all();

                        return $this->render('credit', [
                                'user' => $user,
                                'userProducer' => $userProducer,
                                'creditForm' => $creditForm,
                                'history' => $history
                        ]);
                } else {
                        throw new UserException("Vous ne pouvez pas créditer un utilisateur qui n'est pas associé à votre établissement.");
                }
        }

        /**
         * Affiche les commandes d'un utilisateur.
         *
         * @param integer $id
         * @return mixed
         */
        public function actionOrders($id)
        {
                $user = User::findOne($id);

                $ordersArray = Order::searchAll([
                        'id_user' => $id
                ], ['orderby' => 'distribution.date DESC']);

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

        /**
         * Modifie l'option "credit_active" d'un utilisateur pour le producteur courant.
         * Redirige vers la page de crédit de l'utilisateur.
         *
         * @param integer $idUser
         * @param boolean $state
         */
        public function actionStateCredit($idUser, $state)
        {
                $userProducer = UserProducer::searchOne([
                        'id_user' => $idUser
                ]);

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

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

        /**
         * Finds the User model based on its primary key value.
         * If the model is not found, a 404 HTTP exception will be thrown.
         * @param integer $id
         * @return User the loaded model
         * @throws NotFoundHttpException if the model cannot be found
         */
        protected function findModel($id)
        {
                if (($model = User::findOne($id)) !== null) {
                        return $model;
                } else {
                        throw new NotFoundHttpException('The requested page does not exist.');
                }
        }

}
