@file:Suppress("HardCodedStringLiteral")

package eu.gaudian.translator.model.communication

import eu.gaudian.translator.utils.Log
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit

object RetrofitClient {

    private const val W_BASE_URL = "https://en.wiktionary.org/"

    private val okHttpClient = OkHttpClient.Builder()
        .addInterceptor { chain ->
            val pkg = try { eu.gaudian.translator.BuildConfig.APPLICATION_ID } catch (_: Exception) { "eu.gaudian.translator" }
            val ver = try { eu.gaudian.translator.BuildConfig.VERSION_NAME } catch (_: Exception) { "unknown" }
            val ua = "GaudianTranslator/$ver ($pkg; contact: jonas@gaudian.eu)"
            val request = chain.request().newBuilder()
                .header("User-Agent", ua)
                .build()
            chain.proceed(request)
        }
        .build()

    val api: WiktionaryApiService by lazy {
        Log.d("RetrofitClient", "Creating Wiktionary API with baseUrl=$W_BASE_URL")
        // TODO: Ensure User-Agent complies with Wiktionary API policy; consider including app version.
        val gson = com.google.gson.GsonBuilder()
            .registerTypeAdapter(TextField::class.java, TextFieldDeserializer())
            .create()
        Retrofit.Builder()
            .baseUrl(W_BASE_URL)
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build()
            .create(WiktionaryApiService::class.java)
    }

    private fun normalizeBaseUrl(input: String): String {
        var url = input.trim()
        if (url.isEmpty()) return "http://localhost/"
        // If scheme missing, prepend http://
        if (!url.startsWith("http://") && !url.startsWith("https://")) {
            url = "http://$url"
        }
        // If it's just host:port or IP without trailing slash, ensure trailing slash
        if (!url.endsWith('/')) {
            url += "/"
        }
        return url
    }

    private val logCollector = InMemoryLogCollector()

    /**
     * Creates a Retrofit instance for a specific API provider.
     * @param apiKey The API key for authorization.
     * @param baseUrl The base URL of the API provider (e.g., "https://api.openai.com/").
     * @param provider The ApiProvider object, used to determine which headers to add.
     * @return A configured Retrofit instance.
     */
    fun getApiClient(apiKey: String, baseUrl: String, provider: ApiProvider): Retrofit {
        Log.d("RetrofitClient", "Creating API client with baseUrl=$baseUrl")

        val loggingInterceptor = UserVisibleLoggingInterceptor(logCollector)

        val client = OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(120, TimeUnit.SECONDS)
            .writeTimeout(60, TimeUnit.SECONDS)
            .addInterceptor(loggingInterceptor)
            .addInterceptor { chain ->
                val requestBuilder = chain.request().newBuilder()
                Log.d("RetrofitClient", "Adding headers to request: $requestBuilder")

                val trimmedKey = apiKey.trim()
                when (provider.key) {
                    "gemini" -> {
                        if (trimmedKey.isNotEmpty()) {
                            // Google Generative Language API typically accepts API key as query param `key`.
                            // We also send the x-goog-api-key header for compatibility.
                            requestBuilder.addHeader("x-goog-api-key", trimmedKey)

                            try {
                                val originalUrl = chain.request().url
                                val hasKeyParam = (0 until originalUrl.querySize).any { i ->
                                    originalUrl.queryParameterName(i).equals("key", ignoreCase = true)
                                }
                                val newUrl = if (!hasKeyParam) {
                                    originalUrl.newBuilder().addQueryParameter("key", trimmedKey).build()
                                } else {
                                    originalUrl
                                }
                                requestBuilder.url(newUrl)
                            } catch (_: Exception) {
                                // Fail-safe: if URL manipulation fails, rely on header only.
                            }
                        }
                    }
                    "openrouter" -> {
                        if (trimmedKey.isNotEmpty()) {
                            // Use Bearer token for OpenRouter and add custom headers.
                            requestBuilder.addHeader("Authorization", "Bearer $trimmedKey")
                            requestBuilder.addHeader("HTTP-Referer", "https://gaudian.eu/translator")
                            requestBuilder.addHeader("X-Title", "Gaudian Translator")
                        }
                    }
                    else -> {
                        // Default to the standard Bearer token for most other APIs, but only if key is present.
                        if (trimmedKey.isNotEmpty()) {
                            requestBuilder.addHeader("Authorization", "Bearer $trimmedKey")
                        }
                    }
                }
                chain.proceed(requestBuilder.build())
            }
            .build()

        val normalizedBaseUrl = normalizeBaseUrl(baseUrl)
        Log.d("RetrofitClient", "Normalized baseUrl: $normalizedBaseUrl")

        return Retrofit.Builder()
            .baseUrl(normalizedBaseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .client(client)
            .build()
    }
}

class UserVisibleLoggingInterceptor(private val logCollector: LogCollector) : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()

        val requestLog = StringBuilder().apply {
            append("Request: ${request.method} ${request.url}\n")
            request.headers.forEach { header ->
                append("${header.first}: ${header.second}\n")
            }
        }.toString()
        logCollector.addLog(requestLog)

        val response = chain.proceed(request)

        val responseLog = StringBuilder().apply {
            append("Response: ${response.code} ${response.message}\n")
            response.headers.forEach { header ->
                append("${header.first}: ${header.second}\n")
            }
        }.toString()
        logCollector.addLog(responseLog)

        return response
    }
}

interface LogCollector {
    fun addLog(message: String)
    fun getLogs(): List<String>
}

class InMemoryLogCollector : LogCollector {
    private val logs = mutableListOf<String>()
    private val maxLogs = 100 // Keep last 100 messages

    override fun addLog(message: String) {
        synchronized(logs) {
            logs.add(message)
            if (logs.size > maxLogs) {
                logs.removeAt(0)
            }
        }
    }

    override fun getLogs(): List<String> {
        return synchronized(logs) {
            logs.toList()
        }
    }
}