<?php

namespace App\Imports;

use App\Enums\QuestionExplanationTypeEnum;
use App\Enums\QuestionTypeEnum;
use App\Exceptions\CustomWebException;
use App\Models\Level;
use App\Models\QuestionLevel;
use App\Models\Quiz;
use App\Models\QuizQuestion;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\WithHeadingRow;

class QuizzesImport implements ToCollection, WithHeadingRow
{
    public function __construct(
        public Quiz $quiz
    ) {}

    public function collection(Collection $rows)
    {
        $required_fields = [
            'question',
            'question_type',
            'correct_answers',
            'option_a',
            'option_b',
        ];

        DB::transaction(function () use ($rows, $required_fields) {
            foreach ($rows as $key => $row) {
                $row = collect($row)->mapWithKeys(fn ($value, $key) => [Str::snake(trim($key)) => $value])->toArray();
                $position = $key + 1;
                foreach ($required_fields as $field) {
                    if (empty($row[$field])) {
                        throw new CustomWebException(__("Row #{$position} has no {$field} or {$field} is required"));
                    }
                }

                $questionLevelId = $this->getQuestionLevelId($row, $this->quiz);

                $this->createQuizQuestion($row, $this->quiz, $questionLevelId, $position);
            }
        });
    }

    private function getQuestionLevelId(array $row, Quiz $quiz)
    {
        if (! $quiz->has_level) {
            return null;
        }

        if (empty($row['level'])) {
            throw new CustomWebException(__('One of the row has no level or Level is required'));
        }

        $level = Level::firstOrCreate(['title' => $row['level']]);

        $questionLevel = QuestionLevel::firstOrCreate([
            'quiz_id' => $quiz->id,
            'level_id' => $level->id,
        ]);

        return $questionLevel->id;
    }

    private function createQuizQuestion(array $row, Quiz $quiz, ?int $questionLevelId, int $position)
    {
        if (empty($row['question'])) {
            return;
        }

        $explanation_type = Str::lower($row['explanation_type'] ?? 'text');

        if ($explanation_type && in_array($explanation_type, QuestionExplanationTypeEnum::values())) {
            $explanation_type = QuestionExplanationTypeEnum::from($explanation_type)->value;
        } else {
            throw new CustomWebException(__('Invalid explanation type'));
        }

        $question_type = Str::lower($row['question_type'] ?? 'text');

        if ($question_type && in_array($question_type, QuestionTypeEnum::values())) {
            $question_type = QuestionTypeEnum::from($question_type)->value;
        } else {
            throw new CustomWebException(__('Invalid question type'));
        }

        $question = QuizQuestion::create([
            'quiz_id' => $quiz->id,
            'question_level_id' => $questionLevelId,
            'explanation_type' => $explanation_type,
            'time_limit' => $row['time_limit'] ?? 0,
            'order' => $row['order'] ?? $position,
            'question_type' => $question_type,
            'options' => $this->normalizeOptions($row),
            'correct_answers' => array_filter(explode(',', $row['correct_answers'] ?? '')),
            'score' => $row['score'] ?? 0,
        ]);

        $question->translations()->create([
            'locale' => 'en',
            'question_text' => $row['question'],
            'question_explanation' => $row['explanation'] ?? null,
            'hints' => $row['hints'] ?? null,
            'answer_explanation' => $row['answer_explanation'] ?? null,
        ]);

    }

    private function normalizeOptions($row)
    {
        // key is start with options
        $options = collect($row)->filter(fn ($value, $key) => Str::startsWith($key, 'option'))->toArray();

        $updatedOptions = [];
        foreach ($options as $key => $value) {
            $key = str_replace('option_', '', $key);
            $updatedOptions[] = [
                'label' => $value,
                'value' => ucfirst($key),
            ];
        }

        return $updatedOptions;
    }
}
