<?php

namespace App\Http\Controllers\Admin\Quiz;

use App\Exceptions\CustomWebException;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Quiz\QuizQuestionRequest;
use App\Imports\QuizzesImport;
use App\Models\Quiz;
use App\Models\QuizQuestion;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Maatwebsite\Excel\Facades\Excel;

class QuestionController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index(Quiz $quiz)
    {
        adminUserHasPermission(permission: 'read');

        $questionLevel = $this->getQuestionLevel($quiz);

        $buttons = [
            [
                'label' => __('Add New Question With AI'),
                'icon' => 'ph ph-plus',
                'type' => 'link',
                'link' => route('admin.quizzes.questions.create.ai', ['quiz' => $quiz->id, 'label' => $questionLevel ? $questionLevel->level->slug : null]),
            ],
            [
                'label' => __('Add New Question With Manual'),
                'icon' => 'ph ph-plus',
                'type' => 'link',
                'link' => route('admin.quizzes.questions.create', ['quiz' => $quiz->id, 'label' => $questionLevel ? $questionLevel->level->slug : null]),
            ],
            [
                'label' => __('Add Translation With AI'),
                'icon' => 'ph ph-plus',
                'type' => 'link',
                'link' => route('admin.quizzes.questions.edit.ai', ['quiz' => $quiz->id, 'label' => $questionLevel ? $questionLevel->level->slug : null]),
            ],
            [
                'label' => __('Bulk Import'),
                'icon' => 'ph ph-file-xls',
                'type' => 'modal',
                'href' => route('admin.quiz.bulk-import', ['quiz' => $quiz->id, 'label' => $questionLevel ? $questionLevel->level->slug : null]),
                'id' => 'quiz_import_modal',
            ],
            [
                'label' => __('Back'),
                'icon' => 'ph ph-arrow-clockwise',
                'type' => 'link',
                'link' => $questionLevel ? route('admin.quizzes.question-levels.index', ['quiz' => $quiz->id]) : route('admin.quizzes.index'),
            ],
        ];

        $questions = ($questionLevel ?: $quiz)->questions()->with(['quiz'])->orderBy('order', 'asc')->get();

        return view('admin.pages.quiz.questions.index', compact('questions', 'quiz', 'buttons', 'questionLevel'));
    }

    public function create(Quiz $quiz)
    {
        adminUserHasPermission(permission: 'create');

        $questionLevel = $this->getQuestionLevel($quiz);

        $buttons = [
            [
                'label' => __('Back'),
                'icon' => 'ph ph-arrow-clockwise',
                'type' => 'link',
                'link' => route('admin.quizzes.questions.index', ['quiz' => $quiz->id, 'label' => $questionLevel ? $questionLevel->level->slug : null]),
            ],
        ];

        return view('admin.pages.quiz.questions.create', compact('buttons', 'quiz', 'questionLevel'));
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(QuizQuestionRequest $request, Quiz $quiz)
    {
        adminUserHasPermission(permission: 'create');

        try {
            DB::beginTransaction();

            $question = $quiz->questions()->create($request->questionValidatedData());

            $question->translations()->updateOrCreate(
                ['locale' => $request->locale],
                $request->langValidated()
            );

            DB::commit();
        } catch (\Throwable $th) {
            DB::rollBack();

            throw new CustomWebException($th->getMessage());
        }

        $questionLevel = $this->getQuestionLevel($quiz);

        return response()->json([
            'message' => __('Quiz was successfully created'),
            'redirect' => route('admin.quizzes.questions.index', ['quiz' => $quiz->id, 'label' => $questionLevel ? $questionLevel->level->slug : null]),
        ]);
    }

    public function edit(Quiz $quiz, QuizQuestion $question)
    {
        adminUserHasPermission(permission: 'edit');

        $questionLevel = $this->getQuestionLevel($quiz);

        $this->checkQuestionAuthorization($quiz, $question, $questionLevel);

        $buttons = [
            [
                'label' => __('Back'),
                'icon' => 'ph ph-arrow-clockwise',
                'type' => 'link',
                'link' => route('admin.quizzes.questions.index', ['quiz' => $quiz->id, 'label' => $questionLevel ? $questionLevel->level->slug : null]),
            ],
        ];

        $question->load('translations');
        $question->lang = $question->translations->mapWithKeys(function ($translation) {
            return [$translation->locale => $translation->toArray()];
        })->toArray();

        return view('admin.pages.quiz.questions.edit', compact('quiz', 'question', 'buttons', 'questionLevel'));
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(QuizQuestionRequest $request, Quiz $quiz, QuizQuestion $question)
    {
        adminUserHasPermission(permission: 'edit');

        $questionLevel = $this->getQuestionLevel($quiz);

        $this->checkQuestionAuthorization($quiz, $question, $questionLevel);

        try {
            DB::beginTransaction();

            $questionData = $request->questionValidatedData();

            if (! empty($questionData)) {
                $question->update($questionData);
            }

            $question->translations()->updateOrCreate(
                ['locale' => $request->locale],
                $request->langValidated()
            );

            DB::commit();
        } catch (\Throwable $th) {
            DB::rollBack();

            throw new CustomWebException($th->getMessage());
        }

        return response()->json([
            'message' => __('Quiz was successfully updated'),
            'reload' => true,
        ]);
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(Quiz $quiz, QuizQuestion $question)
    {
        adminUserHasPermission(permission: 'delete');

        $questionLevel = $this->getQuestionLevel($quiz);

        $this->checkQuestionAuthorization($quiz, $question, $questionLevel);

        try {
            DB::beginTransaction();

            $question->translations()->delete();

            $question->delete();

            DB::commit();
        } catch (\Throwable $th) {
            DB::rollBack();

            throw new CustomWebException($th->getMessage());
        }

        return response()->json([
            'message' => __('Quiz was successfully deleted'),
            'reload' => true,
        ]);
    }

    /**
     * Checks if the given QuizQuestion is authorized to be used with the given Quiz.
     * Checks if the question level provided is valid for the given Quiz and QuizQuestion.
     * Throws a CustomWebException if the question is not authorized.
     *
     * @param  mixed  $QuestionLevel
     * @return void
     *
     * @throws CustomWebException
     */
    private function checkQuestionAuthorization(Quiz $quiz, QuizQuestion $quizQuestion, $questionLevel = null)
    {

        if ($questionLevel && ($questionLevel->quiz_id !== $quiz->id || $questionLevel->id !== $quizQuestion->question_level_id)) {
            throw new CustomWebException(__('Unauthorized action'));
        }

        if ($quizQuestion->quiz_id !== $quiz->id) {
            throw new CustomWebException(__('Unauthorized action'));
        }
    }

    /**
     * Update the order of quiz questions.
     *
     * Validates the request to ensure the questions are provided as an array with existing IDs and integer order values.
     * Checks if the user has permission to edit and verifies question authorization within the quiz.
     * Updates the order of each quiz question within a database transaction.
     *
     * @param  \App\Models\QuizQuestion  $question
     * @return \Illuminate\Http\JsonResponse
     *
     * @throws \App\Exceptions\CustomWebException if question is not found or an error occurs during update
     */
    public function updateOrder(Request $request, Quiz $quiz)
    {
        adminUserHasPermission(permission: 'edit');

        $validatedData = $request->validate([
            'questions' => 'required|array',
            'questions.*.id' => 'required|exists:quiz_questions,id',
            'questions.*.order' => 'required|integer|min:1',
        ]);

        try {
            DB::transaction(function () use ($validatedData, $quiz) {
                foreach ($validatedData['questions'] as $data) {
                    $quizQuestion = QuizQuestion::find($data['id']);
                    if (! $quizQuestion) {
                        throw new CustomWebException(__('Question not found'));
                    }
                    $this->checkQuestionAuthorization($quiz, $quizQuestion);
                    $quizQuestion->update(['order' => $data['order']]);
                }
            });
        } catch (\Throwable $th) {
            throw new CustomWebException(__('An error occurred while updating the order'), 0, $th);
        }

        return response()->json([
            'message' => __('Order was successfully updated'),
            'reload' => true,
        ]);
    }

    public function bulkImport(Request $request, Quiz $quiz)
    {
        $request->validate([
            'file' => ['required', 'mimes:xlsx,xls,csv'],
        ]);

        Excel::import(new QuizzesImport($quiz), $request->file('file'));

        return response()->json([
            'message' => __('Questions were successfully imported'),
            'reload' => true,
        ]);
    }

    protected function getQuestionLevel(Quiz $quiz)
    {
        $questionLevel = \request('level');

        if ($questionLevel) {
            $questionLevel = $quiz->QuestionLevels()->whereRelation('level', 'slug', $questionLevel)->first();
        }

        $question_level_id = \request('question_level_id');

        if ($question_level_id) {
            $questionLevel = $quiz->QuestionLevels()->where('id', $question_level_id)->first();
        }

        return $questionLevel;
    }
}
