<?php

namespace common\modules\testings\controllers;

use Yii;
use yii\web\NotFoundHttpException;
use yii\helpers\Json;

use common\modules\testings\models\Test;
use common\modules\testings\models\Passing;
use common\modules\testings\models\QuestionPassing;

class TestController extends \common\components\BaseController
{
	public static function actionsTitles()
	{
		return array(
			'Info' => 'Начало теста',
			'Pass' => 'Тестирование',
			'Finish-test' => 'Завершение теста',
			'Set-answer' => 'Запись ответа на вопрос',
			'Gen-pass' => 'Генерация тестирования',
			'Statistic' => 'Статистика тестирования',
            'Send-not-attempt' => 'Отправка письма при использовании попыток',
		);
	}

	public function actionInfo($id)
	{
		$model = $this->findModel($id);

		if(
			$model 
			// && $model->user_id == Yii::app()->request->cookies[self::AUTH_COOKIE]->value
			// && $model->status == TestingPassing::NOT_STARTED
		)
		{
			return $this->render('info', [
				'model' => $model
			]);
		}
		else
		{
			throw new NotFoundHttpException('The requested page does not exist.');
		}
	}

	public function actionSendNotAttempt($id)
	{
		if(Yii::$app->request->isAjax)
		{
			$passing = $this->findModel($id);

			if($model && $model->sendNotAttempt(Yii::$app->request->post('message')))
			{
				echo Json::encode([
					'success' => true,
					'message' => 'Сообщение отправлено!'
				]);
			}
		}
		else
		{
			throw new NotFoundHttpException('The requested page does not exist.');
		}
		
	}

	public function actionSetAnswer($id)
	{
		if(Yii::$app->request->isAjax)
		{
			header('Content-type: application/json');
			
			$passing = $this->findModel($id);

			$pq = QuestionPassing::find()->where([
				'question_id' => $_POST['question_id'],
				'passing_id' => $passing->id,
			])->one();

			$pq->user_answer = $_POST['userAnswer'];
			$pq->answer_time = ceil($_POST['time']);

            if($pq->save())
            {
				$passing->recountPassResult();
				$passing->percent_rights = $passing->getPercent();

				if($passing->is_passed == Passing::PASSED)
				{
					$passing->pass_date = date('d.m.Y H:i:s');
				}

				$passing->save();

            	return Json::encode([
					'success' => true,
					'percent' => $pq->passing->percent,
				]);
            }
            else
            {
            	return Json::encode([
					'massage' => 'Временные неполадки на сервере, попробуйте еще раз.'
				]);
            }		
		}
		else
		{
			throw new NotFoundHttpException('The requested page does not exist.');
		}
	}

	public function actionFinishTest($id)
	{
		if(Yii::$app->request->isPost)
		{      
			header('Content-type: application/json');

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

			// если тест сдан, результаты модифицировать нельзя
			if ($passing->pass_date === null) 
			{
				$passing->pass_date = date('d.m.Y H:i:s');

				$passing->recountPassResult();

				$passing->percent_rights = $passing->getPercent();

                $passing->save();

				return Json::encode(['status' => 'ok']);
			} 
			else 
			{
				return Json::encode(['massage'=>'Тест уже был сдан!']);
			}
		}
		else
		{
			throw new NotFoundHttpException('The requested page does not exist.');
		}
	}

	public function actionGenPass($id)
	{
		$transaction = Yii::$app->db->beginTransaction();

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

		try 
        {
        	$passing = Passing::find()->where([
        		'user_id' => Yii::$app->user->identity->id,
        		'test_id' => $id
        	])->one();

        	if(!$passing)
        	{
        		$passing = new Passing;
        		$passing->user_id = Yii::$app->user->identity->id;
        		$passing->test_id = $id;
        	}

        	$transaction->commit();
        } 
        catch (\Exception $e) 
        {
            $transaction->rollBack();
            throw $e;
        }




		$user_id = Yii::app()->request->cookies[self::AUTH_COOKIE]->value;
		$cr3 = new CDbCriteria;
		$cr3->with = 'test.session';
		$cr3->addCondition('user_id = :user_id');
		$cr3->addCondition('t.id = :p_id');
		//$cr3->addCondition('t.is_passed is NULL');
		$cr3->addCondition('STR_TO_DATE(`session`.`start_date`,"%d.%m.%Y %H:%i") <= NOW()');
		$cr3->addCondition('(STR_TO_DATE(`session`.`end_date`,"%d.%m.%Y %H:%i") > NOW()) OR (STR_TO_DATE(`t`.`end_date`,"%d.%m.%Y %H:%i") > NOW())');
		$cr3->params = array(
			'user_id' => $user_id,
			'p_id' => $id
		);
		$cr3->group = 't.id';
		$cr3->together = true;

		$tp = TestingPassing::model()->find($cr3);

		if (empty($tp)) 
		{
			echo 'Доступ к этому тесту запрещен';
		}
		else 
		{
			// только проверив состояния, можно допустить юзера к тесту
			switch ($passing->status) 
			{
				case TestingPassing::NOT_STARTED :
					$passing->pass_date_start = date('d.m.Y H:i:s');
					break;
				case TestingPassing::MISTAKE :
					Yii::app()->end();
					break;
				case TestingPassing::STARTED :
					$this->redirect(Yii::app()->createUrl('/testings/testingTest/pass', array('id' => $passing->id)));
					Yii::app()->end();
					break;
				case null :
					break;
				case TestingPassing::FAILED :
				case TestingPassing::PASSED :
					$this->render('pass_statistics', array(
						'model' => $passing,
					));
					Yii::app()->end();
					break;
			}

			if($passing->test->mix)
			{
				// Если данные не заполнены не генерируем вопросы к прохождению
				if($passing->test->minutes && $passing->test->questions && $passing->test->pass_percent && $passing->test->attempt)
				{
					$criteria = new CDbCriteria;

					$criteria->with = 'test';
					$criteria->together = true;

					$criteria->addCondition('test.session_id = ' . $passing->test->session_id);
					$criteria->addCondition('t.user_id = ' . $user_id);
					$criteria->addCondition('test.id <> ' . $passing->test->id);

					$criteria->group = 'test.id';

					$passes = TestingPassing::model()->findAll($criteria);

					if($passes)
					{
						// Проверяем хватает ли вопросов в назначенных пользователю тестах
						$questions_count = 0;
						foreach ($passes as $pass) 
						{
							$questions_count += count($pass->test->questionsRelation);
						}

						if($questions_count >= $passing->test->questions)
						{
							// определение количества вопросов, которое нужно взять из каждого теста
							$need_count_questions = ceil($passing->test->questions / count($passes));

							// Берем все вопросы по тестам
							$questions = array();
							$backup = 0;
							foreach ($passes as $pass) 
							{
								$cr = new CDbCriteria;
								$cr->addCondition('test_id = :test_id');
								$cr->addCondition('is_active = :is_active');
								$cr->params = array(
									':test_id' => $pass->test_id,
									':is_active' => TestingQuestion::ACTIVE,
								);
								$test_questions = TestingQuestion::model()->findAll($cr);
								$count_questions = count($test_questions);

								$questions_needed_in_this_test = $need_count_questions + $backup;

								if($questions_needed_in_this_test > $count_questions) 
								{
									$backup = abs($questions_needed_in_this_test - $count_questions);
									$questions_needed_in_this_test = $count_questions;
								} 
								else 
								{
									$backup = 0;
								}

								shuffle($test_questions);

								for ($i = 1; $i <= $questions_needed_in_this_test; $i++) 
								{
									if(count($questions) < $passing->test->questions)
									{
										$questions[] = array_shift($test_questions);
									}
								}
							}

							shuffle($questions);

							if (count($questions) < $passing->test->questions) 
							{
								$diff = abs(count($questions) - $passing->test->questions);
								Yii::app()->user->setFlash('flash',"В назначенных тестах не хватило несколько вопросов ($diff) для заполнения микса! Обратитесь к администратору.");
							}

							if (count($questions) == $passing->test->questions) 
							{
								$passing->is_passed = 0;
								if ($passing->save()) 
								{
									// сначала на всякий случай чистим старые вопросы. вдруг да остались из-за какого глюка..
									$old_questions = TestingQuestionPassing::model()->findAll('passing_id = :passing_id',array(':passing_id' => $passing->id));
									foreach ($old_questions as $old_q) 
									{
										$old_q->delete();
									}

									// а вот теперь заполняем новыми вопросами
									foreach ($questions as $question) 
									{
										$pq = new TestingQuestionPassing;
										$pq->passing_id = $passing->id;
										$pq->question_id = $question->id;
										$pq->question_text = $question->text;
										$pq->answer_text = $question->rightAnswer;
										$pq->save();
									}
								}
							}
						}
						else
						{
							Yii::app()->user->setFlash('flash',"В назначенных тестах не хватает вопросов для заполнения микса! Обратитесь к администратору.");
						}
					}
					else
					{
						Yii::app()->user->setFlash('flash',"Не хватает назначенных тестов для заполнения микса! Обратитесь к администратору.");
					}

					if (($passing->pass_date === null) && ($passing->is_passed === null)) 
					{
						$this->render('info', array(
							'model' => $passing
						));
						Yii::app()->end();
					}
				}
				else
				{
					$this->redirect(Yii::app()->createUrl('/testings/testingTest/index'));
				}				
			}
			else
			{
				// заполнение списка гамм выбранными пользователем, генерация списка вопросов
				if (isset($_POST['mg']) || isset($_POST['te'])) {
					$mg_array = array();
					$te_array = array();
					if (isset($_POST['mg'])) {
						foreach ($_POST['mg'] as $gamma_id) {
							$gamma = TestingGamma::model()->findByPk($gamma_id);
							if ($gamma) {
								$mg_array[] = $gamma;
							}
						}
					}
					if (isset($_POST['te'])) {
						foreach ($_POST['te'] as $gamma_id) {
							$gamma = TestingGamma::model()->findByPk($gamma_id);
							if ($gamma) {
								$te_array[] = $gamma;
							}
						}
					}
					// если выбрано достаточное кол-во гамм продукции, делаем выбор вопросов и начинаем тестирование
					if ((count($mg_array) >= $passing->test->mg_count) && (count($te_array) >= $passing->test->te_count)) {
						// определение количества вопросов, которое нужно взять из каждой основной гаммы
						$mg_questions_count = round($passing->test->questions * $passing->test->mg_percent / ($passing->test->mg_percent + $passing->test->te_percent));
						$te_questions_count = $passing->test->questions - $mg_questions_count;
						// определение количества вопросов, которое нужно взять из каждой гаммы продукции
						$mg_questions_in_each_gamma = count($mg_array) ? ceil($mg_questions_count / count($mg_array)) : 0;
						$te_questions_in_each_gamma = count($te_array) ? ceil($te_questions_count / count($te_array)) : 0;
						// выбор вопросов для строительной гаммы
						$questions = array();
						$backup = 0; // кол-во вопросов, которое не хватило в какой-нибудь другой гамме
						foreach (array_reverse($mg_array) as $gamma) {
							$cr = new CDbCriteria;
							$cr->addCondition('gamma_id = :gamma_id');
							$cr->addCondition('test_id = :test_id');
							$cr->addCondition('is_active = :is_active');
							$cr->params = array(
								':gamma_id' => $gamma->id,
								':test_id' => $passing->test_id,
								':is_active' => TestingQuestion::ACTIVE,
							);
							$questions_needed_in_this_gamma = $mg_questions_in_each_gamma + $backup;
							$questions_in_gamma = TestingQuestion::model()->findAll($cr);
							$count_questions_in_gamma = count($questions_in_gamma);
							// если нужно вопросов больше, чем есть в этой гамме, просим поддержки у остальных гамм
							if ($questions_needed_in_this_gamma > $count_questions_in_gamma) {
								$backup = abs($questions_needed_in_this_gamma - $count_questions_in_gamma);
								$questions_needed_in_this_gamma = $count_questions_in_gamma;
							} else {
								$backup = 0;
							}
							shuffle($questions_in_gamma);
							for ($i=1; $i<=$questions_needed_in_this_gamma; $i++) {
								$questions[] = array_shift($questions_in_gamma);
							}
						}
						foreach (array_reverse($te_array) as $gamma) {
							$cr = new CDbCriteria;
							$cr->addCondition('gamma_id = :gamma_id');
							$cr->addCondition('test_id = :test_id');
							$cr->addCondition('is_active = :is_active');
							$cr->params = array(
								':gamma_id' => $gamma->id,
								':test_id' => $passing->test_id,
								':is_active' => TestingQuestion::ACTIVE,
							);
							$questions_needed_in_this_gamma = $te_questions_in_each_gamma + $backup;
							$questions_in_gamma = TestingQuestion::model()->findAll($cr);
							$count_questions_in_gamma = count($questions_in_gamma);
							// если нужно вопросов больше, чем есть в этой гамме, просим поддержки у остальных гамм
							if ($questions_needed_in_this_gamma > $count_questions_in_gamma) {
								$backup = abs($questions_needed_in_this_gamma - $count_questions_in_gamma);
								$questions_needed_in_this_gamma = $count_questions_in_gamma;
							} else {
								$backup = 0;
							}
							shuffle($questions_in_gamma);
							for ($i=1; $i<=$questions_needed_in_this_gamma; $i++) {
								$questions[] = array_shift($questions_in_gamma);
							}
						}
						// рандомизируем вопросы
						shuffle($questions);
						// если вопросов получилось БОЛЬШЕ, чем надо (погрешности при округлении в большую сторону),
						// тогда убираем несколько лишних
						if (count($questions) > $passing->test->questions) {
							$diff = count($questions) - $passing->test->questions;
							for ($i=1; $i<=$diff; $i++) {
								array_shift($questions);
							}
						}
						// если вопросов получилось МЕНЬШЕ, чем надо,
						// значит вопросов в гаммах не хватило, выводим сообщение пользователю
						if (count($questions) < $passing->test->questions) {
							$diff = abs(count($questions) - $passing->test->questions);
							Yii::app()->user->setFlash('flash',"В выбранных гаммах не хватило несколько вопросов ($diff) для заполнения теста! Обратитесь к администратору.");
						}

						// и вот, если наконец-то всё ок: вопросы выбраны, количество идеально -
						// заполняем базу вопросами и разрешаем юзеру пройти тест
						if (count($questions) == $passing->test->questions) {
							$passing->is_passed = 0;
							if ($passing->save()) {
								// сначала на всякий случай чистим старые вопросы. вдруг да остались из-за какого глюка..
								$old_questions = TestingQuestionPassing::model()->findAll('passing_id = :passing_id',array(':passing_id'=>$passing->id));
								foreach ($old_questions as $old_q) {
									$old_q->delete();
								}
								// а вот теперь заполняем новыми вопросами
								foreach ($questions as $question) {
									$pq = new TestingQuestionPassing;
									$pq->passing_id = $passing->id;
									$pq->question_id = $question->id;
									$pq->question_text = $question->text;
									$pq->answer_text = $question->rightAnswer;
									$pq->save();
								}
							}
						}

					} else {
						Yii::app()->user->setFlash('flash','Выбрано недостаточное количество гамм продукции!');
						foreach ($mg_array as $item) {
							array_unshift($mg_gammas, $item->id);
						}
						foreach ($te_array as $item) {
							array_unshift($te_gammas, $item->id);
						}
					}
				}

				if (($passing->pass_date === null) && ($passing->is_passed === null)) {
					$this->render('pass_fill_gammas', array(
						'model' => $passing,
						'mg_gammas' => $mg_gammas,
						'te_gammas' => $te_gammas,
					));
					Yii::app()->end();
				}
			}

			if (($passing->pass_date === null) && ($passing->is_passed === TestingPassing::FAILED)) 
			{
				$this->redirect(Yii::app()->createUrl('/testings/test/pass', array('id' => $passing->id)));
			} 
			else 
			{
				$this->redirect(Yii::app()->createUrl('/testings/test/statistic', array('id' => $passing->id)));
			}
		}
	}

	public function actionPass($id)
	{
		$passing = $this->findModel($id);

		switch ($passing->status) 
		{
			case Passing::STARTED :
				$passing->attempt += 1;
				$passing->save(false, ['attempt']);

				$count_answer = QuestionPassing::find()->where(['passing_id' => $id])->andWhere(['not', 'user_answer', null])->count();

				return $this->render('pass_testing', [
					'model' => $passing,
					'current_answer' => $count_answer + 1
				]);
				break;

			case Passing::FAILED :
				if($passing->attempt < $passing->test->attempt && strtotime($passing->pass_date_start) + ($passing->test->minutes * 60) >= time())
				{
					return $this->redirect(['/testings/test/statistic', 'id' => $passing->id]);
				}
				else
				{
					if($passing->attempt >= $passing->test->attempt)
					{
						return $this->render('pass_not_attempt', [
							'model' => $passing,
						]);
					}
					elseif(strtotime($passing->pass_date_start) + ($passing->test->minutes * 60) < time())
					{
						return $this->render('pass_not_time', [
							'model' => $passing,
						]);
					}
					return;
				}
				break;

			case Passing::PASSED :
				return $this->redirect(['/testings/test/statistic', 'id' => $passing->id]);
				break;
		}
	}

	public function actionStatistic($id)
	{
		$passing = $this->findModel($id);

		switch ($passing->status) 
		{
			case TestingPassing::FAILED :
			case TestingPassing::PASSED :
				return $this->render('pass_statistics', [
					'model' => $passing,
				]);
				break;

			default :
				return $this->redirect(['/testings/test/index']);
				break;
		}
	}

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