<?php

namespace App\Http\Controllers;

use Exception;
use App\Models\Term;
use App\Models\User;
use App\Models\Academy;
use App\Models\Question;
use App\Models\UserAttempt;
use Illuminate\Http\Request;
use App\Mail\AssessmentCompleted;
use Illuminate\Support\Facades\DB;
use App\Models\UserQuestionAnswers;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Mail;
use Illuminate\Validation\Validator;
use App\Http\Resources\QuestionResource;
use Illuminate\Validation\ValidationException;

class ApiAssesmentController extends Controller
{
    public function getAssesmentData(Request $request, Academy $academy)
    {
        $user = User::with('attempt', 'questions.answers')->where('guid', $request->guid ?? null)->first();

        if (!$user) {
            return api()->error()->send();
        }

        //if the api call doesn't provide the academy id in the routes, 
        //try to find it from the user's previous attempt
        if (!$academy && $user->attempt()->exists()) {
            $academy = $user->attempt->academy;
        }

        if (!$academy) {
            return api()->error()->customMessage(__("general.academy_not_found"))->send();
        }

        $academy->load('question_types');
        $academyAssessmentDuration = $academy->duration;

        //if start time is filled, the user has started the main part of the test: the questions
        if (!is_null($user->attempt->start_time)) {
            $academyAssessmentDuration = $this->calculateRemainingTime($user->attempt->start_time, $academyAssessmentDuration);
            $questions = $user->questions;
        } else {
            $user->attempt->update(['start_time' => \Carbon\Carbon::now('Europe/Skopje')]);

            $questions = $academy->randomQuestions;
            $user->questions()->attach($questions->pluck('id'));
        }

        $finalData = [
            'duration' => $academyAssessmentDuration,
            'questions' => QuestionResource::collection($user->questions()->get()),
        ];

        return api()->success()->data($finalData)->send();
    }


    public function storeAssesmentData(Request $request)
    {
        $request->validate([
            'guid' => 'required|string|max:60|min:60',
            'question_id' => 'required',
            'question_answer_id' => 'required',
        ]);

        $user = User::where('guid', $request->guid)->first();

        if (!$user) {
            return api()->error()->send();
        }

        //Check if the time has elapsed. If it has, return that info to the 
        //frontend app so it can redirect the user to the result page
        $academy = Academy::find($user->attempt->academy_id);
        $academyAssessmentDuration = $this->calculateRemainingTime($user->attempt->start_time, $academy->duration);
        if ($academyAssessmentDuration == 0) {
            return api()->success()->data(['finished' => true])->send();
        }

        $userQuestionAnswers = UserQuestionAnswers::where('user_id', $user->id)
            ->where('question_id', $request->question_id)
            ->first();

        if (!$userQuestionAnswers) {
            return api()->error()->send();
        }

        $userQuestionAnswers->update([
            'question_answer_id' => $request->question_answer_id,
            'window_out' => $request->window_out ?? null
        ]);

        //After all questions have been answered,
        //save the end time and send email to the user
        if ($user->hasAnsweredAllQuestions()) {
            //update the end time
            $user->attempt->update(['end_time' => \Carbon\Carbon::now('Europe/Skopje')]);


            $message = (new AssessmentCompleted($user))
                ->onConnection('database')
                ->onQueue('emails');

            Mail::to($user)
                ->locale(App::currentLocale())
                ->queue($message);

            return api()->success()->data(['finished' => true])->send();
        }

        return api()->success()->data(['finished' => false])->send();
    }

    public function startMemoryMatrix(Request $request)
    {
        $request->validate([
            'guid' => 'required|string|max:60|min:60'
        ]);

        $user = User::where('guid', $request->guid)->first();

        if (!$user) {
            return api()->error()->send();
        }

        $academy = Academy::find($user->attempt->academy_id);
        $memoryMatrixDuration = $academy->memory_matrix_duration;
        //if memory_matrix_start_time time is filled, the user has started the memory part of the test
        if (!is_null($user->attempt->memory_matrix_start_time)) {
            $memoryMatrixDuration = $this->calculateRemainingTime($user->attempt->memory_matrix_start_time, $academy->memory_matrix_duration);
            if ($memoryMatrixDuration == 0) {
                return api()->success()->data(['finished' => true])->send();
            }
        } else {
            $user->attempt->update(['memory_matrix_start_time' => \Carbon\Carbon::now('Europe/Skopje')]);
        }

        $finalData = [
            'duration' => $memoryMatrixDuration
        ];

        return api()->success()->data($finalData)->send();
    }


    public function storeMemoryMatrixResult(Request $request)
    {
        $request->validate([
            'guid' => 'required|string|max:60|min:60',
            'result' => 'required',
            'level' => 'required',
            'sublevel' => 'required'
        ]);

        $user = User::where('guid', $request->guid)->first();

        if (!$user) {
            return api()->error()->send();
        }

        $user->attempt->update(['memory_matrix_end_time' => \Carbon\Carbon::now('Europe/Skopje')]);
        $user->attempt->update(['memory_matrix_result' => $request->result]);
        $user->attempt->update(['memory_matrix_level' => $request->level]);
        $user->attempt->update(['memory_matrix_sublevel' => $request->sublevel]);

        return api()->success()->send();
    }

    public function startSpeedArithmetic(Request $request)
    {
        $request->validate([
            'guid' => 'required|string|max:60|min:60'
        ]);

        $user = User::where('guid', $request->guid)->first();

        if (!$user) {
            return api()->error()->send();
        }

        $academy = Academy::find($user->attempt->academy_id);
        $speedArithmeticDuration = $academy->speed_arithmetic_duration;
        //if speed_arithmetic_start_time time is filled, the user has started the memory part of the test
        if (!is_null($user->attempt->speed_arithmetic_start_time)) {
            $speedArithmeticDuration = $this->calculateRemainingTime($user->attempt->speed_arithmetic_start_time, $academy->speed_arithmetic_duration);
            if ($speedArithmeticDuration == 0) {
                return api()->success()->data(['finished' => true])->send();
            }
        } else {
            $user->attempt->update(['speed_arithmetic_start_time' => \Carbon\Carbon::now('Europe/Skopje')]);
        }

        $finalData = [
            'duration' => $speedArithmeticDuration
        ];

        return api()->success()->data($finalData)->send();
    }


    public function storeSpeedArithmeticResult(Request $request)
    {
        $request->validate([
            'guid' => 'required|string|max:60|min:60',
            'result' => 'required'
        ]);

        $user = User::where('guid', $request->guid)->first();

        if (!$user) {
            return api()->error()->send();
        }

        $user->attempt->update(['speed_arithmetic_end_time' => \Carbon\Carbon::now('Europe/Skopje')]);
        $user->attempt->update(['speed_arithmetic_result' => $request->result]);

        return api()->success()->send();
    }

    public function getUserRemainingTime(Request $request)
    {
        $user = User::where('guid', $request->guid ?? null)->with('attempt')->first();

        if (!$user || !$user->attempt) {
            return api()->error()->send();
        }

        $academy = Academy::find($user->attempt->academy_id)->load('question_types');
        $academyAssessmentDuration = $this->calculateRemainingTime($user->attempt->start_time, $academy->duration);

        return api()->success()->data(['duration' => $academyAssessmentDuration])->send();
    }

    private function calculateRemainingTime($startTime, $academyAssessmentDuration)
    {
        $currentTime = \Carbon\Carbon::now('Europe/Skopje');
        //Added 5 seconds threshold to make up for Ajax delays
        $elapsedTime = $currentTime->diffInSeconds($startTime) - 5;

        $remainingTime = $academyAssessmentDuration - $elapsedTime;

        if ($remainingTime <= 0) {
            return 0;
        }

        return $remainingTime;
    }

    public function getResult(Request $request)
    {
        $user = User::with('attempt', 'questions.answers')->where('guid', $request->guid ?? null)->first();
        if (!$user) {
            return api()->error()->send();
        }
        if (!$user->hasAnsweredAllQuestions()) {
            return api()->success()->data(['completed' => false,  'token' => $user->token])->send();
        }

        $latestTerm = Term::orderByDesc('id')->first();
        if (!$latestTerm) {
            return api()->error()->send();
        }

        $score = $user->percentile;

        return api()->success()->data(['completed' => true, 'token' => $user->token, 'score' => $score, 'end_date' => $latestTerm->end_date->format('Y-m-d'), 'results_date' => $latestTerm->results_date->format('Y-m-d')])->send();
    }

    //Send email to students on timeout that their qualifying test is over
    public function handleTimeout(Request $request)
    {
        $request->validate([
            'guid' => 'required|string|max:60|min:60',
        ]);

        $user = User::where('guid', $request->guid)->first();

        if (!$user) {
            return api()->error()->send();
        }

        // $message = (new AssessmentCompleted($user))
        //     ->onConnection('database')
        //     ->onQueue('emails');

        // Mail::to($user)
        //     ->locale(App::currentLocale())
        //     ->queue($message);

        return api()->success()->data(['finished' => true])->send();
    }
}
