<?php

namespace App\Http\Controllers\Admin\Contest;

use App\Exceptions\CustomWebException;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Contest\ContestQuestionRequest;
use App\Imports\ContestImport;
use App\Models\Contest;
use App\Models\ContestQuestion;
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(Contest $contest)
    {
        adminUserHasPermission(permission: 'read');

        $buttons = [
            [
                'label' => __('Add New Question With AI'),
                'icon' => 'ph ph-plus',
                'type' => 'link',
                'link' => route('admin.contests.questions.create.ai', ['contest' => $contest->id]),
            ],
            [
                'label' => __('Add New Question'),
                'icon' => 'ph ph-plus',
                'type' => 'link',
                'link' => route('admin.contests.questions.create', ['contest' => $contest->id]),
            ],
            [
                'label' => __('Add Translation With AI'),
                'icon' => 'ph ph-plus',
                'type' => 'link',
                'link' => route('admin.contests.questions.edit.ai', ['contest' => $contest->id]),
            ],
            [
                'label' => __('Bulk Import'),
                'icon' => 'ph ph-file-xls',
                'type' => 'modal',
                'href' => route('admin.contest.bulk-import', ['contest' => $contest->id]),
                'id' => 'contest_import_modal',
            ],
            [
                'label' => __('Back'),
                'icon' => 'ph ph-arrow-clockwise',
                'type' => 'link',
                'link' => route('admin.contests.index'),
            ],
        ];

        $questions = $contest->questions()->orderBy('order', 'asc')->get();

        return view('admin.pages.contests.questions.index', compact('questions', 'contest', 'buttons'));
    }

    public function create(Contest $contest)
    {
        adminUserHasPermission(permission: 'create');

        $buttons = [
            [
                'label' => __('Back'),
                'icon' => 'ph ph-arrow-clockwise',
                'type' => 'link',
                'link' => route('admin.contests.questions.index', ['contest' => $contest->id]),
            ],
        ];

        return view('admin.pages.contests.questions.create', compact('buttons', 'contest'));
    }

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

        try {
            DB::beginTransaction();

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

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

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

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

        return response()->json([
            'message' => __('Contest was successfully created'),
            'redirect' => route('admin.contests.questions.edit', ['contest' => $contest->id, 'question' => $question->id]),
        ]);
    }

    public function edit(Contest $contest, ContestQuestion $question)
    {
        adminUserHasPermission(permission: 'edit');

        $this->checkQuestionAuthorization($contest, $question);

        $buttons = [
            [
                'label' => __('Back'),
                'icon' => 'ph ph-arrow-clockwise',
                'type' => 'link',
                'link' => route('admin.contests.questions.index', ['contest' => $contest->id]),
            ],
        ];

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

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

    /**
     * Update the specified resource in storage.
     */
    public function update(ContestQuestionRequest $request, Contest $contest, ContestQuestion $question)
    {
        adminUserHasPermission(permission: 'edit');

        $this->checkQuestionAuthorization($contest, $question);

        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' => __('Contest was successfully updated'),
            'redirect' => route('admin.contests.questions.index', ['contest' => $contest->id]),
        ]);
    }

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

        $this->checkQuestionAuthorization($contest, $question);

        try {
            DB::beginTransaction();

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

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

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

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

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

        Excel::import(new ContestImport($contest), $request->file('file'));

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

    /**
     * Check if the given contest question is authorized to be used with the given contest.
     * Checks if the question belongs to the given contest.
     * Throws a CustomWebException if the question is not authorized.
     *
     * @return void
     *
     * @throws CustomWebException
     */
    private function checkQuestionAuthorization(Contest $contest, ContestQuestion $contestQuestion)
    {
        if ($contestQuestion->contest_id !== $contest->id) {
            throw new CustomWebException(__('Question does not belong to this contest'));
        }
    }

    /**
     * Update the order of contest 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 contest.
     * Updates the order of each contest question within a database transaction.
     *
     * @param  \App\Models\ContestQuestion  $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, Contest $contest)
    {
        adminUserHasPermission(permission: 'edit');

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

        try {
            DB::transaction(function () use ($validatedData, $contest) {
                foreach ($validatedData['questions'] as $data) {
                    $contestQuestion = ContestQuestion::find($data['id']);
                    if (! $contestQuestion) {
                        throw new CustomWebException(__('Question not found'));
                    }
                    $this->checkQuestionAuthorization($contest, $contestQuestion);
                    $contestQuestion->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,
        ]);
    }
}
