@file:Suppress("HardCodedStringLiteral")

package eu.gaudian.translator.utils

import android.content.Context
import eu.gaudian.translator.model.Exercise
import eu.gaudian.translator.model.Question
import eu.gaudian.translator.model.VocabularyItem
import eu.gaudian.translator.model.communication.ApiManager
import eu.gaudian.translator.model.communication.ModelType
import eu.gaudian.translator.model.repository.LanguageRepository
import kotlinx.coroutines.flow.first
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import kotlin.reflect.KClass

private const val TAG = "ExerciseService"

class ExerciseService(val context: Context) {

    private val apiRequestHandler = ApiRequestHandler(ApiManager(context), context)
    private val languageRepository = LanguageRepository(context)
    private val jsonHelper = JsonHelper()

    /**
     * Generates 10 vocabulary items for a given exercise title.
     * @return A list of the newly created VocabularyItems.
     */
    suspend fun generateAndSaveVocabularyForExercise(exerciseTitle: String): List<VocabularyItem> {
        val sourceLang = languageRepository.loadSelectedSourceLanguage().first()
        val targetLang = languageRepository.loadSelectedTargetLanguage().first()

        if (sourceLang == null || targetLang == null) {
            Log.w(TAG, "Source or target language not selected. Skipping vocabulary generation.")
            return emptyList()
        }

        val prompt = ExercisePromptGenerator.generateVocabularyPrompt(exerciseTitle, sourceLang.englishName, targetLang.englishName)
        val response = makeApiRequest(prompt)

        val vocabItems = parseVocabularyFromJson(response).map {
            it.copy(languageFirstId = sourceLang.nameResId, languageSecondId = targetLang.nameResId)
        }

        return vocabItems
    }

    /**
     * Orchestrates the entire AI generation flow for a new exercise with questions.
     * Returns a Triple with the exercise, questions, and new vocabulary.
     */
    suspend fun generateExerciseWithQuestions(
        category: String,
        questionTypes: List<KClass<out Question>>,
        difficulty: String,
        amount: Int,
        sourceLanguage: String? = null,
        targetLanguage: String? = null,
        progressUpdater: ((String) -> Unit)? = null
    ): Triple<Exercise, List<Question>, List<VocabularyItem>>? {
        try {
            progressUpdater?.invoke("generateExerciseShellPrompt")
            val exercisePrompt = ExercisePromptGenerator.generateExerciseShellPrompt(category)
            val exerciseResponse = makeApiRequest(exercisePrompt)
            val (exerciseId, exerciseTitle) = ExerciseParser.parseExerciseShell(exerciseResponse)
                ?: throw Exception("Failed to parse exercise shell")

            val effectiveSource = sourceLanguage ?: languageRepository.loadSelectedSourceLanguage().first()?.englishName
            val effectiveTarget = targetLanguage ?: languageRepository.loadSelectedTargetLanguage().first()?.englishName

            progressUpdater?.invoke("generateVocabularyPrompt")
            val newVocabulary = generateAndSaveVocabularyForExercise(exerciseTitle)
            val words = newVocabulary.map { it.wordSecond }

            // Generate context passage for this exercise (dialogue or text, depending on difficulty)
            progressUpdater?.invoke("generateContextPrompt")
            val contextPrompt = ExercisePromptGenerator.generateContextPrompt(
                category = category,
                difficulty = difficulty,
                languageFirst = effectiveSource,
                languageSecond = effectiveTarget
            )
            val contextResponse = makeApiRequest(contextPrompt)
            progressUpdater?.invoke("parseExerciseContext")
            val context = ExerciseParser.parseExerciseContext(contextResponse)
            val contextTitle = context?.first ?: ""
            val contextText = context?.second ?: ""

            // Batch questions generation to max 10 per request
            val batches = mutableListOf<Int>()
            var remaining = amount
            while (remaining > 0) {
                val size = minOf(10, remaining)
                batches.add(size)
                remaining -= size
            }
            val allQuestions = mutableListOf<Question>()

            for ((index, batchSize) in batches.withIndex()) {
                progressUpdater?.invoke("generateQuestionsPrompt ${index + 1}/${batches.size}")
                val questionsPrompt = ExercisePromptGenerator.generateQuestionsPrompt(
                    exerciseTitle = exerciseTitle,
                    optionalVocabulary = words,
                    questionTypes = questionTypes,
                    difficulty = difficulty,
                    amount = batchSize,
                    languageFirst = effectiveSource!!,
                    languageSecond = effectiveTarget!!,
                    contextText = contextText.ifBlank { null }
                )
                Log.d(TAG, "Questions prompt: $questionsPrompt")
                val questionsResponse = makeApiRequest(questionsPrompt)
                progressUpdater?.invoke("parseQuestions ${index + 1}/${batches.size}")
                val batchQuestions = ExerciseParser.parseQuestions(questionsResponse)
                if (batchQuestions.isEmpty()) {
                    Log.w(TAG, "Batch ${index + 1} returned 0 questions")
                } else {
                    allQuestions.addAll(batchQuestions)
                }
            }

            if (allQuestions.isEmpty()) {
                throw Exception("AI failed to generate any valid questions.")
            }

            val finalExercise = Exercise(
                id = exerciseId,
                title = exerciseTitle,
                questions = allQuestions.map { it.id },
                associatedVocabularyIds = newVocabulary.map { it.id },
                sourceLanguage = effectiveSource,
                targetLanguage = effectiveTarget,
                contextTitle = contextTitle.ifBlank { null },
                contextText = contextText.ifBlank { null }
            )

            return Triple(finalExercise, allQuestions, newVocabulary)

        } catch (e: Exception) {
            Log.e(TAG, "Error generating exercise with questions: ${e.message}", e)
            return null
        }
    }

    /**
     * Generates questions based on YouTube video subtitles using AI.
     * @param subtitles List of subtitle lines from the video
     * @param videoTitle Title of the video
     * @param sourceLanguage Source language code (optional)
     * @param targetLanguage Target language code (optional)
     * @param progressUpdater Callback for progress updates (optional)
     * @return List of generated questions
     */
    suspend fun generateQuestionsFromSubtitles(
        subtitles: List<eu.gaudian.translator.model.SubtitleLine>,
        videoTitle: String,
        sourceLanguage: String? = null,
        targetLanguage: String? = null,
        progressUpdater: ((String) -> Unit)? = null
    ): List<Question> {
        Log.d(TAG, "Generating questions from subtitles...")
        try {
            if (subtitles.isEmpty()) {
                throw Exception("No subtitles provided for question generation")
            }

            progressUpdater?.invoke("Preparing video content for AI analysis...")

            // Combine subtitles into a coherent text
            val fullText = subtitles.joinToString(" ") { it.text }
            val translatedText = subtitles.filter { it.translatedText != null }
                .joinToString(" ") { it.translatedText!! }

            sourceLanguage ?: languageRepository.loadSelectedSourceLanguage().first()?.englishName
            val effectiveTarget = targetLanguage ?: languageRepository.loadSelectedTargetLanguage().first()?.englishName

            progressUpdater?.invoke("Generating questions with AI...")

            // Create a prompt for generating questions based on video content
            val prompt = buildString {
                append("Generate 8 diverse, high-quality questions based on this YouTube video content.\n\n")
                append("Video Title: $videoTitle\n\n")
                append("Video Content (Original Language):\n$fullText\n\n")

                if (translatedText.isNotEmpty()) {
                    append("Video Content (Translated to $effectiveTarget):\n$translatedText\n\n")
                }

                append("Requirements:\n")
                append("- Create a mix of question types: True/False, Multiple Choice, Fill-in-the-blank, Word Order\n")
                append("- Questions should test comprehension of the video content\n")
                append("- Include questions about key facts, concepts, and vocabulary from the video\n")
                append("- Make questions challenging but fair\n")
                append("- Provide clear, unambiguous correct answers\n")
                append("- If using non-English content, include appropriate language questions\n\n")

                append("Return the questions in this exact JSON format:\n")
                append("[\n")
                append("  {\n")
                append("    \"type\": \"TrueFalseQuestion\",\n")
                append("    \"name\": \"Question text?\",\n")
                append("    \"correctAnswer\": true/false,\n")
                append("    \"explanation\": \"Why this is correct\"\n")
                append("  },\n")
                append("  {\n")
                append("    \"type\": \"MultipleChoiceQuestion\",\n")
                append("    \"name\": \"Question text?\",\n")
                append("    \"options\": [\"Option A\", \"Option B\", \"Option C\", \"Option D\"],\n")
                append("    \"correctAnswerIndex\": 0\n")
                append("  },\n")
                append("  {\n")
                append("    \"type\": \"FillInTheBlankQuestion\",\n")
                append("    \"name\": \"Question with ___ blank\",\n")
                append("    \"correctAnswer\": \"correct answer\"\n")
                append("  },\n")
                append("  {\n")
                append("    \"type\": \"WordOrderQuestion\",\n")
                append("    \"name\": \"Rearrange the words to form a sentence from the video:\",\n")
                append("    \"words\": [\"word1\", \"word2\", \"word3\"],\n")
                append("    \"correctOrder\": [\"word1\", \"word2\", \"word3\"]\n")
                append("  }\n")
                append("]\n")
            }

            val response = makeApiRequest(prompt)

            progressUpdater?.invoke("Parsing AI-generated questions...")

            // Parse the JSON response and convert to Question objects
            return parseVideoQuestionsFromJson(response)

        } catch (e: Exception) {
            Log.e(TAG, "Error generating questions from subtitles: ${e.message}", e)
            // Fallback to simple question generation if AI fails
            return generateSimpleQuestionsFromSubtitles(subtitles)
        }
    }

    private fun parseVideoQuestionsFromJson(jsonResponse: String): List<Question> {
        val questions = mutableListOf<Question>()
        var nextId = 1

        try {
            // Simple JSON parsing for the expected format
            val json = jsonResponse.trim()

            // Extract question objects from JSON array
            val questionMatches = Regex("\\{[^}]*\"type\"\\s*:\\s*\"([^\"]+)\"[^}]*\\}").findAll(json)

            for (match in questionMatches) {
                val questionJson = match.value
                val type = Regex("\"type\"\\s*:\\s*\"([^\"]+)\"").find(questionJson)?.groupValues?.get(1)

                when (type) {
                    "TrueFalseQuestion" -> {
                        val name = extractJsonString(questionJson, "name")
                        val correctAnswer = extractJsonBoolean(questionJson, "correctAnswer")
                        val explanation = extractJsonString(questionJson, "explanation")

                        if (name != null && correctAnswer != null) {
                            questions.add(
                                eu.gaudian.translator.model.TrueFalseQuestion(
                                    id = nextId++,
                                    name = name,
                                    correctAnswer = correctAnswer,
                                    explanation = explanation ?: "Based on the video content"
                                )
                            )
                        }
                    }
                    "MultipleChoiceQuestion" -> {
                        val name = extractJsonString(questionJson, "name")
                        val options = extractJsonStringArray(questionJson, "options")
                        val correctIndex = extractJsonInt(questionJson, "correctAnswerIndex")

                        if (name != null && options != null && correctIndex != null && correctIndex < options.size) {
                            questions.add(
                                eu.gaudian.translator.model.MultipleChoiceQuestion(
                                    id = nextId++,
                                    name = name,
                                    options = options,
                                    correctAnswerIndex = correctIndex
                                )
                            )
                        }
                    }
                    "FillInTheBlankQuestion" -> {
                        val name = extractJsonString(questionJson, "name")
                        val correctAnswer = extractJsonString(questionJson, "correctAnswer")

                        if (name != null && correctAnswer != null) {
                            questions.add(
                                eu.gaudian.translator.model.FillInTheBlankQuestion(
                                    id = nextId++,
                                    name = name,
                                    correctAnswer = correctAnswer
                                )
                            )
                        }
                    }
                    "WordOrderQuestion" -> {
                        val name = extractJsonString(questionJson, "name")
                        val words = extractJsonStringArray(questionJson, "words")
                        val correctOrder = extractJsonStringArray(questionJson, "correctOrder")

                        if (name != null && words != null && correctOrder != null) {
                            questions.add(
                                eu.gaudian.translator.model.WordOrderQuestion(
                                    id = nextId++,
                                    name = name,
                                    words = words,
                                    correctOrder = correctOrder
                                )
                            )
                        }
                    }
                }
            }
        } catch (e: Exception) {
            Log.e(TAG, "Error parsing video questions JSON: ${e.message}", e)
        }

        return questions
    }

    private fun extractJsonString(json: String, key: String): String? {
        val regex = Regex("\"$key\"\\s*:\\s*\"([^\"]+)\"")
        return regex.find(json)?.groupValues?.get(1)
    }

    private fun extractJsonBoolean(json: String, key: String): Boolean? {
        val regex = Regex("\"$key\"\\s*:\\s*(true|false)")
        return regex.find(json)?.groupValues?.get(1)?.toBoolean()
    }

    private fun extractJsonInt(json: String, key: String): Int? {
        val regex = Regex("\"$key\"\\s*:\\s*(\\d+)")
        return regex.find(json)?.groupValues?.get(1)?.toInt()
    }

    private fun extractJsonStringArray(json: String, key: String): List<String>? {
        @Suppress("RegExpRedundantEscape") val regex = Regex("\"$key\"\\s*:\\s*\\[([^\\]]+)\\]")
        val match = regex.find(json) ?: return null
        val arrayContent = match.groupValues[1]

        return arrayContent.split(",").map { it.trim().removeSurrounding("\"").trim() }
    }

    private fun generateSimpleQuestionsFromSubtitles(
        subtitles: List<eu.gaudian.translator.model.SubtitleLine>
    ): List<Question> {
        // Fallback to the simple generation method if AI fails
        val questions = mutableListOf<Question>()
        var nextId = 1

        val meaningfulSubtitles = subtitles.filter { it.text.length > 10 }
        if (meaningfulSubtitles.isEmpty()) return emptyList()

        // Generate simple questions as fallback
        meaningfulSubtitles.take(3).forEach { subtitle ->
            val statement = subtitle.text.trim()
            if (statement.length > 20 && statement.contains(" ") && !statement.endsWith("?")) {
                questions.add(
                    eu.gaudian.translator.model.TrueFalseQuestion(
                        id = nextId++,
                        name = "According to the video: $statement",
                        correctAnswer = true,
                        explanation = "This statement appears in the video content."
                    )
                )
            }
        }

        return questions
    }

    /**
     * Parses vocabulary items from JSON response using the enhanced JsonHelper
     */
    private fun parseVocabularyFromJson(jsonResponse: String): List<VocabularyItem> {
        return try {
            // Clean and validate the JSON first
            val cleanedJson = jsonHelper.cleanAndValidateJson(jsonResponse)

            // Parse the JSON object for vocabulary items
            val jsonObject = kotlinx.serialization.json.Json.parseToJsonElement(cleanedJson).jsonObject

            val vocabularyItems = mutableListOf<VocabularyItem>()
            var id = 1

            for ((wordFirst, wordSecondElement) in jsonObject) {
                val wordSecond = wordSecondElement.jsonPrimitive.content.trim()
                val vocabularyItem = VocabularyItem(
                    id = id++,
                    languageFirstId = -1, // Will be set by caller
                    languageSecondId = -1, // Will be set by caller
                    wordFirst = wordFirst.trim(),
                    wordSecond = wordSecond
                )
                vocabularyItems.add(vocabularyItem)
            }

            vocabularyItems
        } catch (e: Exception) {
            Log.e(TAG, "Error parsing vocabulary from JSON: ${e.message}", e)
            emptyList()
        }
    }

    private suspend fun makeApiRequest(prompt: String): String {
        val template = DynamicJsonRequest(prompt, ModelType.EXERCISE, "ExerciseService")
        val result = apiRequestHandler.executeRequest(template)

        return if (result.isSuccess) {
            result.getOrNull().toString()
        } else {
            throw result.exceptionOrNull() ?: Exception("API request failed without exception")
        }
    }
}