<?php

namespace common\modules\event\controllers;

use common\components\RoleDefinition;
use common\manager\EventRegistrationManager;
use common\models\CardEventRegistrationForm;
use common\models\EventEquipmentType;
use common\models\EventEquipmentTypeAssignment;
use common\models\EventRegistration;
use common\models\EventRegistrationEquipmentTypeAssignment;
use common\models\Trainer;
use common\modules\event\EventModule;
use common\modules\event\modelAndView\CreateEventModelAndView;
use common\modules\event\models\copy\ClearWeekForm;
use common\modules\event\models\copy\CopyWeekSearch;
use common\modules\event\models\EventCreate;
use common\modules\event\models\EventEquipmentTypeForm;
use common\modules\event\models\EventPermissions;
use common\modules\event\models\timetable\TimeTableSearch;
use DateTime;
use Exception;
use Throwable;
use Yii;
use common\models\Event;
use common\modules\event\models\EventSearch;
use yii\data\ActiveDataProvider;
use yii\filters\AccessControl;
use yii\web\BadRequestHttpException;
use yii\web\Controller;
use yii\web\HttpException;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use yii\web\Response;
use yii\web\UnauthorizedHttpException;

/** @noinspection PhpUnused */

/**
 * EventController implements the CRUD actions for Event model.
 */
class EventController extends Controller
{
    public function behaviors()
    {
        $behaviors = [
            'verbs' => [
                'class' => VerbFilter::class,
                'actions' => [
                    'delete' => ['post'],
                ],
            ],
        ];

        $module = EventModule::getInstance();
        assert(isset($module), 'event module not set');
        $allowedActions = ['index', 'view', 'reserve-card', 'cancel-registration', 'delete-registration', 'timetable', 'copy-week', 'clear-week',];
        if ($module->mode === 'backend') {
            $allowedActions[] = 'create';
            $allowedActions[] = 'update';
            $allowedActions[] = 'delete';
            $allowedActions[] = 'equipment-types-assignment';
        }
        $behaviors['access'] = [
            'class' => AccessControl::class,
            'rules' => [
                // allow authenticated users
                [
                    'actions' => $allowedActions,
                    'allow' => true,
                    'roles' => ['@'],
                ],
                // everything else is denied
            ],
        ];

        return $behaviors;
    }

    /**
     * Lists all Event models.
     * @return mixed
     */
    public function actionIndex()
    {
        $searchModel = new EventSearch();
        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);

        $permissions = new EventPermissions();

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

    /**
     * Displays a single Event model.
     * @param integer $id
     * @return mixed
     * @throws NotFoundHttpException
     */
    public function actionView($id)
    {
        $eventRegistrationManager = new EventRegistrationManager();

        $dataProvider = new ActiveDataProvider([
                'query' => $eventRegistrationManager->createFindRegistrationsQuery($id),
            ]
        );

        $equipmentAssignmentDataProvider = new ActiveDataProvider([
                'query' => EventEquipmentTypeAssignment::find()->andWhere(['id_event' => $id]),
            ]
        );
        return $this->render('view', [
            'model' => $this->findModel($id),
            'dataProvider' => $dataProvider,
            'equipmentAssignmentDataProvider' => $equipmentAssignmentDataProvider,
            'permissions' => new EventPermissions()
        ]);
    }

    /**
     * Creates a new Event model.
     * If creation is successful, the browser will be redirected to the 'view' page.
     * @return mixed
     */
    public function actionCreate()
    {
        if ( !RoleDefinition::canAny([RoleDefinition::$ROLE_TRAINER, RoleDefinition::$ROLE_ADMIN])){
            throw new UnauthorizedHttpException();
        }

        $modelAndView = new CreateEventModelAndView();

        $event = new EventCreate();
        $event->id_user = \Yii::$app->user->id;

        $modelAndView->event = $event;

        $query = Trainer::find();
        if (RoleDefinition::isAdmin() == false) {
            $query = $query->innerJoinWith('userTrainerAssignments')
                ->andWhere(
                    [
                        'user_trainer_assignment.id_user' => \Yii::$app->user->id
                    ]
                );
        }
        $trainers = $query->all();

        $modelAndView->trainers = $trainers;

        /** @noinspection NotOptimalIfConditionsInspection */
        if ($event->load(Yii::$app->request->post()) && $event->save()) {
            return $this->redirect(['view', 'id' => $event->id]);
        }

        return $this->render('create', [
            'modelAndView' => $modelAndView
        ]);
    }

    /**
     * Updates an existing Event model.
     * If update is successful, the browser will be redirected to the 'view' page.
     * @param integer $id
     * @return mixed
     * @throws NotFoundHttpException
     */
    public function actionUpdate($id)
    {
        if ( !RoleDefinition::canAny([RoleDefinition::$ROLE_TRAINER, RoleDefinition::$ROLE_ADMIN])){
            throw new UnauthorizedHttpException();
        }
        $modelAndView = new CreateEventModelAndView();
        $event = EventCreate::findOne($id);
        if ( !isset($event)){
            throw new NotFoundHttpException();
        }

        $modelAndView->event = $event;

        $trainers = Trainer::getTrainersAllowed(\Yii::$app->user->id);

        if ( !Trainer::isTrainerAllowed($trainers,\Yii::$app->user->id, $event->id_trainer)){
            throw new BadRequestHttpException("Ön nem jogosult az esemény módosítására");
        }

        $modelAndView->trainers = $trainers;


        /** @noinspection NotOptimalIfConditionsInspection */
        if ($event->load(Yii::$app->request->post()) && $event->save()) {
            return $this->redirect(['view', 'id' => $event->id]);
        }

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

    /**
     * Deletes an existing Event model.
     * If deletion is successful, the browser will be redirected to the 'index' page.
     * @param integer $id
     * @return mixed
     * @throws NotFoundHttpException
     * @throws Throwable
     */
    public function actionDelete($id)
    {
        $manager = new EventRegistrationManager();
        $manager->deleteEvent($this->findModel($id));
        return $this->redirect(['index']);
    }/** @noinspection PhpUnused */


    /**
     * @param $id
     * @return Response
     * @throws Exception
     */
    public function actionCancelRegistration($id)
    {
        $eventRegistrationManager = new EventRegistrationManager();
        $db = Yii::$app->db;
        $tx = $db->beginTransaction();
        try {
            $registration = $eventRegistrationManager->loadRegistration($id,null);
            $eventRegistrationManager->cancelRegistrationTX($registration,null,EventRegistration::CANCEL_REASON_CUSTOMER);
            $tx->commit();
            return $this->redirect(['view', 'id' => $registration->id_event]);
        } catch (Exception $ex) {
            $tx->rollBack();
            throw $ex;
        }
    }/** @noinspection PhpUnused */

//    /**
//     * @param $id
//     * @return Response
//     * @throws Exception
//     */
//    public function actionDeleteRegistration($id)
//    {
//        $eventRegistrationManager = new EventRegistrationManager();
//        $db = Yii::$app->db;
//        $tx = $db->beginTransaction();
//        try {
//            $registration = $eventRegistrationManager->loadRegistration($id);
//            $eventRegistrationManager->deleteRegistration($registration);
//            $tx->commit();
//            return $this->redirect(['view', 'id' => $registration->id_event]);
//        } catch (Exception $ex) {
//            $tx->rollBack();
//            throw $ex;
//        }
//    }/** @noinspection PhpUnused */

    /**
     * @param $id
     * @return string|Response
     * @throws NotFoundHttpException
     * @throws Exception
     */
    public function actionReserveCard($id)
    {

        $event = $this->findModel($id);

        $model = new CardEventRegistrationForm();
        $model->event_id = $id;
        if ($model->load(Yii::$app->request->post())) {
            if ($model->validate()) {
                $manager = new EventRegistrationManager();
                try {
                    $manager->registerCard($model);
                } /** @noinspection PhpRedundantCatchClauseInspection */ catch (HttpException $e) {
                    if (array_key_exists($e->getCode(), EventRegistrationManager::$STATES)) {
                        $model->addError('card_number', Yii::t('event-registration', EventRegistrationManager::$STATES[$e->getCode()]));
                    } else {
                        $model->addError('card_number', Yii::t('event-registration', 'Unknown Error'));
                    }
                }
            }
            if ($model->hasErrors()) {
                return $this->render('register_card', [
                    'model' => $model,
                    'event' => $event,
                ]);
            }

            return $this->redirect(['view', 'id' => $id]);
        }
        return $this->render('register_card', [
            'model' => $model,
            'event' => $event,
        ]);
    }

    /** @noinspection PhpUnused */
    /**
     * @return string
     * @throws Exception
     */
    public function actionTimetable()
    {
        $search = new TimeTableSearch();
        $search->startDateString = (new DateTime())->format('Y.m.d');
        $dataProvider = $search->search(Yii::$app->request->get());
        return $this->render('timetable', array(
            'model' => $search,
            'dataProvider' => $dataProvider
        ));
    }

    /** @noinspection PhpUnused */
    /**
     * @return string
     * @throws Exception
     */
    public function actionCopyWeek()
    {
        $model = new CopyWeekSearch();
        $model->sourceDateString = date('Y.m.d');
        $model->targetDateString = date('Y.m.d', strtotime('+1 week'));
        if (Yii::$app->request->isPost) {
            $model->search(Yii::$app->request->post());
            if (count($model->getErrors()) === 0) {
                $model->save();
                $this->redirect(['copy-week', $model->formName() . '[sourceDateString]' => $model->sourceDateString, $model->formName() . '[targetDateString]' => $model->targetDateString]);
            }
        } else {
            $model->search(Yii::$app->request->get());
        }
        return $this->render('copy_week', ['model' => $model]);


    }/** @noinspection PhpUnused */

    /**
     * @return Response
     * @throws Throwable
     */
    public function actionClearWeek()
    {

        $clearWeekForm = new ClearWeekForm();
        $clearWeekForm->clear(Yii::$app->request->get());
        return $this->redirect(['timetable', []]);
    }

    /**
     * @param $id   the id
     * @return string
     * @throws NotFoundHttpException
     */
    public function actionEquipmentTypesAssignment($id)
    {
//        $event = $this->findModel($id);
        $formModel = new EventEquipmentTypeForm(
            ['idEvent' => $id]
        );
        $formModel->loadEvent();
        $formModel->loadAssignedEquipment();
        if (Yii::$app->request->isPost) {
            if ($formModel->load(Yii::$app->request->post()) && $formModel->save()) {
                $this->redirect(['view', 'id' => $formModel->event->id]);
            }
        } else {
            if (!isset($formModel->event)) {
                throw new NotFoundHttpException('The requested page does not exist.');
            }
        }

        $formModel->equipmentTypeList = EventEquipmentType::find()->orderBy(['name' => SORT_ASC])->all();

        return $this->render('equipment-types-assignment', [
            'formModel' => $formModel
        ]);
    }

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

        throw new NotFoundHttpException('The requested page does not exist.');
    }

}
