@file:Suppress("HardCodedStringLiteral")

package eu.gaudian.translator.utils

import android.content.Context
import eu.gaudian.translator.model.LanguageModel
import eu.gaudian.translator.model.communication.ApiLogEntry
import eu.gaudian.translator.model.communication.ApiManager
import eu.gaudian.translator.model.communication.ModelType
import eu.gaudian.translator.model.repository.ApiLogRepository
import eu.gaudian.translator.model.repository.ApiRepository
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.UUID

interface ApiCallback {
    fun onSuccess(translatedText: String?)
    fun onFailure(errorMessage: String)
}

/**
 * Enhanced API request handler that serves as the single entry point for all API calls.
 * Provides unified JSON parsing, error handling, logging, and response validation.
 *
 * This class should be the only component that directly calls ApiManager.getCompletion().
 * All services should use this handler for their API requests.
 */
class ApiRequestHandler(private val apiManager: ApiManager, context: Context) {

    private val apiLogRepository = ApiLogRepository(context)
    private val jsonHelper = JsonHelper()
    val apiRepository = ApiRepository(context)


    /**
     * Executes an API request using a template for type-safe, validated responses.
     * This is the preferred method for all API requests.
     *
     * @param template The request template containing all request configuration
     * @return Result containing the parsed response or error
     */
    suspend fun <T> executeRequest(template: ApiRequestTemplate<T>): Result<T> {

        val languageModel: LanguageModel? = when (template.modelType) {
            ModelType.TRANSLATION -> apiRepository.getTranslationModel().first()
            ModelType.EXERCISE -> apiRepository.getExerciseModel().first()
            ModelType.VOCABULARY -> apiRepository.getVocabularyModel().first()
            ModelType.DICTIONARY -> apiRepository.getDictionaryModel().first()
        }


        return withContext(Dispatchers.IO) {
            val startTime = System.currentTimeMillis()
            var prompt = ""

            try {
                Log.i("ApiRequestHandler", "[${template.serviceName}] Executing API request")

                prompt = template.buildPrompt()
                Log.d("ApiRequestHandler", "[${template.serviceName}] Generated prompt: $prompt")

                val rawResponse = getCompletionFromApi(prompt, template.modelType, template.serviceName)
                val duration = System.currentTimeMillis() - startTime

                if (rawResponse.isFailure) {
                    val error = rawResponse.exceptionOrNull()
                    Log.e("ApiRequestHandler", "[${template.serviceName}] API request failed", error)
                    logInteraction(
                        template, prompt, null, error, duration,
                        providerKey = languageModel?.modelId ?: "",
                        method = template.modelType.name,
                    )
                    return@withContext Result.failure(error!!)
                }

                val responseText = rawResponse.getOrNull()!!
                Log.d("ApiRequestHandler", "[${template.serviceName}] Raw API response: $responseText")

                // Log the successful raw response
                logInteraction(
                    template, prompt, responseText, null, duration,
                    providerKey = languageModel?.modelId ?: "",
                    method = template.modelType.name,
                )

                // Clean the response text to remove conversational wrappers and Markdown fences
                val cleanedResponse = extractJsonFromResponse(responseText)

                // Validate response structure if required fields are specified
                if (template.requiredFields.isNotEmpty()) {
                    if (!jsonHelper.validateRequiredFields(cleanedResponse, template.requiredFields)) {
                        val errorMsg = "Response missing required fields: ${template.requiredFields}"
                        Log.e("ApiRequestHandler", "[${template.serviceName}] $errorMsg")
                        return@withContext Result.failure(ApiValidationException(errorMsg))
                    }
                }

                // Parse the response using the enhanced JsonHelper
                val parseResult = jsonHelper.parseJson(cleanedResponse, template.responseSerializer, template.serviceName)

                if (parseResult.isSuccess) {
                    Log.i("ApiRequestHandler", "[${template.serviceName}] API request completed successfully")
                }

                parseResult
            } catch (e: Exception) {
                val duration = System.currentTimeMillis() - startTime
                Log.e("ApiRequestHandler", "[${template.serviceName}] Unexpected error during API request", e)
                // Log the unexpected exception if we haven't logged a response yet
                logInteraction(
                    template, prompt, null, e, duration,
                    providerKey = languageModel?.modelId ?: "",
                    method = template.modelType.name,
                )
                Result.failure(ApiRequestException("Unexpected error in ${template.serviceName}", e))
            }
        }
    }

    /**
     * Logs the API interaction to the database.
     */
    private fun <T> logInteraction(
        template: ApiRequestTemplate<T>,
        prompt: String,
        response: String?,
        error: Throwable?,
        duration: Long,
        providerKey: String,
        method: String,

    ) {
        try {
            val entry = ApiLogEntry(
                id = UUID.randomUUID().toString(),
                timestamp = System.currentTimeMillis(),
                providerKey = providerKey,
                endpoint = template.serviceName,
                method = method,
                model = template.modelType.name,
                requestJson = prompt,
                responseCode = if (error == null) 200 else 500,
                responseMessage = error?.message ?: "Success",
                responseJson = response,
                errorMessage = error?.message,
                durationMs = duration,
                exceptionType = error?.javaClass?.simpleName,
                isTimeout = false,
                parseErrorMessage = null,
                url = null
            )
            // Fire and forget logging
            CoroutineScope(Dispatchers.IO).launch {
                try {
                    apiLogRepository.addLog(entry)
                } catch (e: Exception) {
                    Log.e("ApiRequestHandler", "Failed to save API log", e)
                }
            }
        } catch (e: Exception) {
            Log.e("ApiRequestHandler", "Failed to create API log entry", e)
        }
    }

    /**
     * Robostly extracts JSON from an API response string.
     * Handles:
     * 1. Markdown code blocks (```json ... ```)
     * 2. Conversational wrapping ("Here is the JSON: ...")
     * 3. Think blocks (<think>...</think>)
     * 4. Raw JSON
     */
    private fun extractJsonFromResponse(text: String): String {
        val trimmed = text.trim()

        // 0. First, strip any <think>...</think> blocks (may contain newlines)
        val thinkRegex = Regex("<think>[\\s\\S]*?</think>")
        val textWithoutThink = thinkRegex.replace(trimmed, "").trim()

        // 1. Try to find content within Markdown code blocks
        // This regex looks for ``` (optional json) ... content ... ```
        val codeBlockRegex = Regex("```(?:json)?\\s*([\\s\\S]*?)\\s*```", RegexOption.IGNORE_CASE)
        val match = codeBlockRegex.find(textWithoutThink)
        if (match != null) {
            return match.groupValues[1].trim()
        }

        // 2. If no code block is found, try to find the outermost JSON structure (Object or Array)
        val firstBrace = textWithoutThink.indexOf('{')
        val firstBracket = textWithoutThink.indexOf('[')

        var startIndex = -1
        var endIndex = -1

        // Determine if we should look for an Object {} or an Array []
        // We pick whichever appears first
        if (firstBrace != -1 && (firstBracket == -1 || firstBrace < firstBracket)) {
            startIndex = firstBrace
            endIndex = textWithoutThink.lastIndexOf('}')
        } else if (firstBracket != -1) {
            startIndex = firstBracket
            endIndex = textWithoutThink.lastIndexOf(']')
        }

        if (startIndex != -1 && endIndex != -1 && endIndex > startIndex) {
            return textWithoutThink.substring(startIndex, endIndex + 1)
        }

        // 3. Fallback: return the text without think blocks (parsing will likely fail if it's not valid JSON)
        return textWithoutThink
    }

    /**
     * Internal method to get completion from API manager.
     * This is the only place that should call ApiManager.getCompletion().
     */
    private suspend fun getCompletionFromApi(
        prompt: String,
        modelType: ModelType,
        serviceName: String
    ): Result<String> {
        val deferred = CompletableDeferred<Result<String>>()



        try {
            apiManager.getCompletion(
                prompt = prompt,
                callback = object : ApiCallback {
                    override fun onSuccess(translatedText: String?) {
                        if (translatedText.isNullOrBlank()) {
                            val errorMsg = "API returned an empty response"
                            Log.e("ApiRequestHandler", "[$serviceName] $errorMsg")
                            deferred.complete(Result.failure(ApiResponseException(errorMsg)))
                            return
                        }
                        Log.d("ApiRequestHandler", "[$serviceName] API response received successfully")
                        deferred.complete(Result.success(translatedText))
                    }

                    override fun onFailure(errorMessage: String) {
                        Log.e("ApiRequestHandler", "[$serviceName] API failure: $errorMessage")
                        deferred.complete(Result.failure(ApiResponseException(errorMessage)))
                    }
                },
                modelType = modelType
            )
        } catch (e: Exception) {
            Log.e("ApiRequestHandler", "[$serviceName] Error calling API manager", e)
            deferred.complete(Result.failure(ApiRequestException("Error calling API manager", e)))
        }

        return deferred.await()
    }
}

/**
 * Custom exception for API request errors.
 */
class ApiRequestException(message: String, cause: Throwable? = null) : Exception(message, cause)

/**
 * Custom exception for API response errors.
 */
class ApiResponseException(message: String, cause: Throwable? = null) : Exception(message, cause)

/**
 * Custom exception for API validation errors.
 */
class ApiValidationException(message: String, cause: Throwable? = null) : Exception(message, cause)
