@file:Suppress("HardCodedStringLiteral")

package eu.gaudian.translator

import android.content.Context
import android.util.Log
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import eu.gaudian.translator.model.communication.ApiManager
import eu.gaudian.translator.utils.ApiRequestHandler
import eu.gaudian.translator.utils.DictionaryDefinitionRequest
import eu.gaudian.translator.utils.TextCorrectionRequest
import eu.gaudian.translator.utils.TextTranslationRequest
import eu.gaudian.translator.utils.VocabularyGenerationRequest
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
import org.junit.Assert.fail
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TestWatcher
import org.junit.runner.Description
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class ApiRequestIntegrationTest {

    private lateinit var context: Context
    private lateinit var apiRequestHandler: ApiRequestHandler
    private lateinit var apiManager: ApiManager

    // TAG for filtering in Logcat
    @Suppress("PrivatePropertyName")
    private val TAG = "ApiTest"

    @get:Rule
    val watcher = object : TestWatcher() {
        override fun starting(description: Description) {
            Log.i(TAG, "🟢 STARTING TEST: ${description.methodName}")
        }

        override fun finished(description: Description) {
            Log.i(TAG, "🏁 FINISHED TEST: ${description.methodName}")
        }

        override fun failed(e: Throwable?, description: Description) {
            Log.e(TAG, "❌ FAILED TEST: ${description.methodName}", e)
        }
    }

    @Before
    fun setup() {
        try {
            Log.d(TAG, "SETUP: Initializing Context...")
            // Use targetContext to access the app's resources/files
            context = InstrumentationRegistry.getInstrumentation().targetContext

            Log.d(TAG, "SETUP: Injecting Test Config into SharedPreferences...")
            // Ensure we use the exact preference file name used by your SettingsRepository
            // Default is usually "package_name_preferences"
            val prefsName = "${context.packageName}_preferences"
            val prefs = context.getSharedPreferences(prefsName, Context.MODE_PRIVATE)

            prefs.edit().apply {
                putString("api_key", TestConfig.API_KEY)
                // If your ApiManager uses a specific settings key for provider, set it here:
                putString("selected_ai_provider", TestConfig.PROVIDER_NAME)
                putString("custom_server_url", TestConfig.BASE_URL)
                commit()
            }
            Log.d(TAG, "SETUP: Config injected. Key present: ${prefs.contains("api_key")}")

            Log.d(TAG, "SETUP: Initializing ApiManager...")
            apiManager = ApiManager(context)

            Log.d(TAG, "SETUP: Initializing ApiRequestHandler...")
            apiRequestHandler = ApiRequestHandler(apiManager, context)

            Log.d(TAG, "SETUP: Complete.")

        } catch (e: Exception) {
            // THIS is what you are missing in the current output
            Log.e(TAG, "🔥 CRITICAL SETUP FAILURE: ${e.message}", e)
            throw e // Re-throw to fail the test, but now it's logged
        }
    }

    @Test
    fun testDictionaryDefinitionRequest() = runBlocking {
        Log.d(TAG, "Testing Dictionary Definition...")
        val template = DictionaryDefinitionRequest(
            word = "Serendipity",
            language = "English",
            requestedParts = "Definition"
        )

        val result = apiRequestHandler.executeRequest(template)

        handleResult(result) { data ->
            assertNotNull("Word should not be null", data.word)
            assertTrue("Parts should not be empty", data.parts.isNotEmpty())
            Log.i(TAG, "✅ Dictionary Success: Defined '${data.word}'")
        }
    }

    @Test
    fun testTextTranslationRequest() = runBlocking {
        Log.d(TAG, "Testing Text Translation...")
        val template = TextTranslationRequest(
            text = "Hello, world!",
            sourceLanguage = "English",
            targetLanguage = "German"
        )

        val result = apiRequestHandler.executeRequest(template)

        handleResult(result) { data ->
            assertNotNull("Translation should not be null", data.translatedText)
            assertTrue("Translation should not be empty", data.translatedText.isNotBlank())
            Log.i(TAG, "✅ Translation Success: '${data.translatedText}'")
        }
    }

    @Test
    fun testCorrectionRequest() = runBlocking {
        Log.d(TAG, "Testing Text Correction...")
        val template = TextCorrectionRequest(
            textToCorrect = "I has went home.",
            language = "English",
            grammarOnly = true,
            tone = null
        )

        val result = apiRequestHandler.executeRequest(template)

        handleResult(result) { data ->
            assertNotEquals("Corrected text should be different", "I has went home.", data.correctedText)
            Log.i(TAG, "✅ Correction Success: -> '${data.correctedText}'")
        }
    }

    @Test
    fun testVocabularyGenerationRequest() = runBlocking {
        Log.d(TAG, "Testing Vocab Generation...")
        val template = VocabularyGenerationRequest(
            category = "Technology",
            languageFirst = "English",
            languageSecond = "Spanish",
            amount = 2
        )

        val result = apiRequestHandler.executeRequest(template)

        handleResult(result) { data ->
            assertEquals("Should receive exactly 2 cards", 2, data.flashcards.size)
            Log.i(TAG, "✅ Vocab Gen Success: Got ${data.flashcards.size} cards")
        }
    }

    /**
     * Helper to log results consistently and fail with clear messages
     */
    private fun <T> handleResult(result: Result<T>, assertions: (T) -> Unit) {
        if (result.isFailure) {
            val error = result.exceptionOrNull()
            Log.e(TAG, "❌ API REQUEST FAILED", error)
            fail("API Request failed with exception: ${error?.message}")
        } else {
            val data = result.getOrNull()!!
            Log.d(TAG, "Received Data: $data")
            assertions(data)
        }
    }
}