@file:Suppress("HardCodedStringLiteral")

package eu.gaudian.translator.utils

import android.content.Context
import eu.gaudian.translator.model.Language
import eu.gaudian.translator.model.communication.ApiManager
import eu.gaudian.translator.model.communication.ModelType
import eu.gaudian.translator.utils.dictionary.DictionaryService
import io.mockk.every
import io.mockk.mockk
import junit.framework.TestCase.assertEquals
import junit.framework.TestCase.assertFalse
import junit.framework.TestCase.assertNotNull
import junit.framework.TestCase.assertTrue
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test

class JsonHelperTest {

    private lateinit var jsonHelper: JsonHelper

    @Before
    fun setup() {
        jsonHelper = JsonHelper()
    }

    @Test
    fun `parseJson should successfully parse valid JSON`() = runTest {
        // Given
        val validJson = """{"word": "hello", "parts": [{"title": "Definition", "content": "A greeting"}]}"""

        // When & Then
        // This test would need proper serializer setup
        // For now, just test the validation
        assertTrue(jsonHelper.validateRequiredFields(validJson, listOf("word", "parts")))
    }

    @Test
    fun `validateRequiredFields should return false for missing fields`() {
        // Given
        val incompleteJson = """{"word": "hello"}"""
        val requiredFields = listOf("word", "parts")

        // When
        val result = jsonHelper.validateRequiredFields(incompleteJson, requiredFields)

        // Then
        assertFalse(result)
    }

    @Test
    fun `validateRequiredFields should return true for complete fields`() {
        // Given
        val completeJson = """{"word": "hello", "parts": []}"""
        val requiredFields = listOf("word", "parts")

        // When
        val result = jsonHelper.validateRequiredFields(completeJson, requiredFields)

        // Then
        assertTrue(result)
    }

    @Test
    fun `extractField should return correct value`() {
        // Given
        val json = """{"word": "hello", "parts": []}"""

        // When
        val result = jsonHelper.extractField(json, "word")

        // Then
        assertEquals("hello", result)
    }

    @Test
    fun `extractField should return null for missing field`() {
        // Given
        val json = """{"word": "hello"}"""

        // When
        val result = jsonHelper.extractField(json, "missing")

        // Then
        assertEquals(null, result)
    }
}

class ApiRequestHandlerTest {

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

    @Before
    fun setup() {
        apiManager = mockk(relaxed = true)
        context = mockk(relaxed = true)
        apiRequestHandler = ApiRequestHandler(apiManager, context)
    }

    @Test
    fun `executeRequest with template should handle successful response`() = runTest {
        // Given
        val template = DictionaryDefinitionRequest(
            word = "test",
            language = "English",
            requestedParts = "Definition"
        )
        
        // Mock the API manager response
        every { 
            apiManager.getCompletion(
                prompt = any(),
                callback = any(),
                modelType = ModelType.DICTIONARY
            )
        } answers {
            val callback = thirdArg<(String?) -> Unit>()
            callback("""{"word": "test", "parts": [{"title": "Definition", "content": "A test"}]}""")
        }

        // When
        val result = apiRequestHandler.executeRequest(template)

        // Then
        assertTrue(result.isSuccess)
        result.getOrNull()?.let { response ->
            assertEquals("test", response.word)
            assertEquals(1, response.parts.size)
        }
    }

    @Test
    fun `executeRequest with template should handle API failure`() = runTest {
        // Given
        val template = DictionaryDefinitionRequest(
            word = "test",
            language = "English",
            requestedParts = "Definition"
        )
        
        every { 
            apiManager.getCompletion(
                prompt = any(),
                callback = any(),
                modelType = ModelType.DICTIONARY
            )
        } answers {
            val callback = secondArg<(String) -> Unit>()
            callback("API Error")
        }

        // When
        val result = apiRequestHandler.executeRequest(template)

        // Then
        assertTrue(result.isFailure)
    }
}

class ApiRequestTemplatesTest {

    @Test
    fun `DictionaryDefinitionRequest should build correct prompt`() {
        // Given
        val template = DictionaryDefinitionRequest(
            word = "hello",
            language = "English",
            requestedParts = "Definition, Origin"
        )

        // When
        val prompt = template.buildPrompt()

        // Then
        assertTrue(prompt.contains("hello"))
        assertTrue(prompt.contains("English"))
        assertTrue(prompt.contains("Definition, Origin"))
        assertTrue(prompt.contains("JSON object"))
    }

    @Test
    fun `VocabularyTranslationRequest should build correct prompt`() {
        // Given
        val words = listOf("hello", "world")
        val template = VocabularyTranslationRequest(
            words = words,
            languageFirst = "English",
            languageSecond = "Spanish"
        )

        // When
        val prompt = template.buildPrompt()

        // Then
        assertTrue(prompt.contains("English"))
        assertTrue(prompt.contains("Spanish"))
        assertTrue(prompt.contains("hello"))
        assertTrue(prompt.contains("world"))
        assertTrue(prompt.contains("flashcards"))
    }

    @Test
    fun `TextCorrectionRequest should build correct prompt`() {
        // Given
        val template = TextCorrectionRequest(
            textToCorrect = "Helo world",
            language = "English",
            grammarOnly = true,
            tone = null
        )

        // When
        val prompt = template.buildPrompt()

        // Then
        assertTrue(prompt.contains("Helo world"))
        assertTrue(prompt.contains("English"))
        assertTrue(prompt.contains("grammar, spelling, and punctuation"))
        assertTrue(prompt.contains("correctedText"))
        assertTrue(prompt.contains("explanation"))
    }

    @Test
    fun `SynonymGenerationRequest should build correct prompt`() {
        // Given
        val template = SynonymGenerationRequest(
            amount = 5,
            language = "English",
            term = "happy",
            translation = "feliz",
            translationLanguage = "Spanish",
            languageCode = "en"
        )

        // When
        val prompt = template.buildPrompt()

        // Then
        assertTrue(prompt.contains("happy"))
        assertTrue(prompt.contains("feliz"))
        assertTrue(prompt.contains("English"))
        assertTrue(prompt.contains("Spanish"))
        assertTrue(prompt.contains("synonyms"))
        assertTrue(prompt.contains("proximity"))
    }
}

class DictionaryServiceTest {

    private lateinit var context: Context
    private lateinit var dictionaryService: DictionaryService

    @Before
    fun setup() {
        context = mockk(relaxed = true)
        dictionaryService = DictionaryService(context)
    }

    @Test
    fun `searchDefinition should handle successful response`() = runTest {
        // This test would require mocking the ApiRequestHandler
        // For now, just verify the method exists and basic structure
        val language = Language(
            name = "English",
            nameResId = 1,
            code = "en",
            englishName = "English",
            region = ""
        )

        // When & Then
        // This would need proper mocking setup
        assertNotNull(language)
        assertEquals("English", language.name)
    }

    @Test
    fun `getExampleSentence should handle successful response`() = runTest {
        val languageFirst = Language(
            name = "English",
            nameResId = 1,
            code = "en",
            englishName = "English",
            region = ""
        )
        
        val languageSecond = Language(
            name = "Spanish",
            nameResId = 2,
            code = "es",
            englishName = "Spanish",
            region = ""
        )

        // When & Then
        assertNotNull(languageFirst)
        assertNotNull(languageSecond)
    }
}

class VocabularyServiceTest {

    private lateinit var context: Context
    private lateinit var vocabularyService: VocabularyService

    @Before
    fun setup() {
        context = mockk(relaxed = true)
        vocabularyService = VocabularyService(context)
    }

    @Test
    fun `translateWordsBatch should handle empty list`() = runTest {
        // Given
        val emptyWords = emptyList<String>()
        val languageFirst = Language(
            name = "English",
            nameResId = 1,
            code = "en",
            englishName = "English",
            region = ""
        )
        
        val languageSecond = Language(
            name = "Spanish",
            nameResId = 2,
            code = "es",
            englishName = "Spanish",
            region = ""
        )

        // When
        val result = vocabularyService.translateWordsBatch(emptyWords, languageFirst, languageSecond)

        // Then
        assertTrue(result.isSuccess)
        assertEquals(0, result.getOrNull()?.size)
    }

    @Test
    fun `translateWordsBatch should filter blank words`() = runTest {
        // Given
        val wordsWithBlanks = listOf("hello", "", "world", "   ")

        // When & Then
        // This would need proper mocking setup for actual API calls
        assertEquals(2, wordsWithBlanks.filter { it.isNotBlank() }.size)
    }

    @Test
    fun `generateSynonyms should use correct parameters`() = runTest {
        // Given
        val language = Language(
            name = "English",
            nameResId = 1,
            code = "en",
            englishName = "English",
            region = ""
        )
        
        val translationLanguage = Language(
            name = "Spanish",
            nameResId = 2,
            code = "es",
            englishName = "Spanish",
            region = ""
        )

        // When & Then
        // This would need proper mocking setup for actual API calls
        assertNotNull(language)
        assertNotNull(translationLanguage)
        assertEquals("English", language.englishName)
        assertEquals("Spanish", translationLanguage.englishName)
    }
}

class TranslationServiceTest {

    private lateinit var context: Context
    private lateinit var translationService: TranslationService

    @Before
    fun setup() {
        context = mockk(relaxed = true)
        translationService = TranslationService(context)
    }

    @Test
    fun `simpleTranslateTo should handle basic translation`() = runTest {
        // Given
        val targetLanguage = Language(
            name = "Spanish",
            nameResId = 1,
            code = "es",
            englishName = "Spanish",
            region = ""
        )

        // When & Then
        // This would need proper mocking setup for actual API calls
        assertNotNull(targetLanguage)
        assertEquals("Spanish", targetLanguage.name)
    }

    @Test
    fun `translateSentence should handle sentence translation`() = runTest {
        // Given
        val sentence = "Hello world"

        // When & Then
        // This would need proper mocking setup for actual API calls
        assertNotNull(sentence)
        assertEquals("Hello world", sentence)
    }
}

class CorrectionServiceTest {

    private lateinit var context: Context
    private lateinit var correctionService: CorrectionService

    @Before
    fun setup() {
        context = mockk(relaxed = true)
        correctionService = CorrectionService(context)
    }

    @Test
    fun `correctText should handle basic correction`() = runTest {
        // Given
        val language = Language(
            name = "English",
            nameResId = 1,
            code = "en",
            englishName = "English",
            region = ""
        )

        // When & Then
        // This would need proper mocking setup for actual API calls
        assertNotNull(language)
        assertEquals("English", language.name)
    }

    @Test
    fun `correctText should handle grammar only mode`() = runTest {
        // Given
        val textToCorrect = "Helo world"
        val language = Language(
            name = "English",
            nameResId = 1,
            code = "en",
            englishName = "English",
            region = ""
        )

        // When & Then
        // This would need proper mocking setup for actual API calls
        assertNotNull(textToCorrect)
        assertNotNull(language)
        assertEquals("Helo world", textToCorrect)
    }
}

// Integration test example
class ApiArchitectureIntegrationTest {

    @Test
    fun `end to end dictionary lookup should work`() = runTest {
        // This would be an integration test that tests the full flow
        // from service -> template -> API handler -> JSON parsing
        
        // Given
        val mockContext = mockk<Context>(relaxed = true)
        val mockApiManager = mockk<ApiManager>(relaxed = true)
        
        // Setup mock API response
        every { 
            mockApiManager.getCompletion(
                prompt = any(),
                callback = any(),
                modelType = ModelType.DICTIONARY
            )
        } answers {
            val callback = thirdArg<(String?) -> Unit>()
            callback("""{"word": "test", "parts": [{"title": "Definition", "content": "A test word"}]}""")
        }

        // When
        val apiHandler = ApiRequestHandler(mockApiManager, mockContext)
        val template = DictionaryDefinitionRequest(
            word = "test",
            language = "English",
            requestedParts = "Definition"
        )
        val result = apiHandler.executeRequest(template)

        // Then
        assertTrue(result.isSuccess)
        result.getOrNull()?.let { response ->
            assertEquals("test", response.word)
            assertEquals(1, response.parts.size)
            assertEquals("Definition", response.parts[0].title)
        }
    }
}
