package com.example.notesai

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.preferencesDataStoreFile
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.example.notesai.data.local.DataStoreManager
import com.example.notesai.data.model.ChatHistory
import com.example.notesai.data.model.ChatMessage
import com.example.notesai.data.model.toSerializable
import com.example.notesai.util.FileParseResult
import com.example.notesai.util.FileParser
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
import java.util.UUID

/**
 * Unit Test untuk File Upload & PDF Summary Functionality
 * Coverage:
 * - TC-06: Upload PDF → summary tersimpan/terbaca
 */
@RunWith(AndroidJUnit4::class)
class FileUploadFunctionalityTest {

    private lateinit var context: Context
    private lateinit var dataStore: DataStore<Preferences>
    private lateinit var dataStoreManager: DataStoreManager
    private lateinit var testScope: CoroutineScope

    @Before
    fun setup() {
        runBlocking {
            context = ApplicationProvider.getApplicationContext()
            testScope = CoroutineScope(SupervisorJob())

            val testDataStoreName = "test_file_upload_prefs_${UUID.randomUUID()}"
            dataStore = PreferenceDataStoreFactory.create(
                scope = testScope,
                produceFile = { context.preferencesDataStoreFile(testDataStoreName) }
            )

            dataStoreManager = DataStoreManager(context)

            // Clear all data before each test
            dataStoreManager.saveChatHistory(emptyList())
        }
    }

    @After
    fun tearDown() {
        testScope.cancel()
    }

    // ================== TC-06: FILE UPLOAD & SUMMARY ==================

    @Test
    fun testFileParseResult_shouldCalculateWordCount() {
        runBlocking {
            // Given - Text with known word count
            val content = "One two three four five words here"

            val fileResult = FileParseResult.Success(
                content = content,
                fileName = "word_count_test.txt",
                fileType = "Text",
                wordCount = content.split(Regex("\\s+")).size
            )

            // Then - Should count words correctly
            assertEquals(7, fileResult.wordCount)
        }
    }

    @Test
    fun testFileParseResult_shouldIdentifyFileType() {
        runBlocking {
            // Given - Different file types
            val pdfResult = FileParseResult.Success(
                content = "PDF content",
                fileName = "test.pdf",
                fileType = "PDF",
                wordCount = 2
            )

            val txtResult = FileParseResult.Success(
                content = "Text content",
                fileName = "test.txt",
                fileType = "Text",
                wordCount = 2
            )

            val docxResult = FileParseResult.Success(
                content = "Word content",
                fileName = "test.docx",
                fileType = "Word",
                wordCount = 2
            )

            // Then - Should identify correctly
            assertEquals("PDF", pdfResult.fileType)
            assertEquals("Text", txtResult.fileType)
            assertEquals("Word", docxResult.fileType)
        }
    }

    @Test
    fun testFileParseError_shouldContainMessage() {
        // Given - Error result
        val errorResult = FileParseResult.Error("File kosong atau tidak dapat dibaca")

        // Then - Should contain error message
        assertEquals("File kosong atau tidak dapat dibaca", errorResult.message)
    }

    @Test
    fun testFormatFileSize_shouldFormatCorrectly() {
        // Given - Different file sizes
        val testCases = mapOf(
            500L to "B",
            1024L to "KB",
            1024L * 1024 to "MB",
            1024L * 1024 * 5 to "MB"
        )

        // When & Then - Format each size
        testCases.forEach { (bytes, expectedUnit) ->
            val formatted = FileParser.formatFileSize(bytes)
            assertTrue("Expected unit $expectedUnit in $formatted",
                formatted.contains(expectedUnit))
        }
    }

    @Test
    fun testSaveSummaryToChatHistory_shouldPersist() {
        runBlocking {
            // Given - Clear existing data
            dataStoreManager.saveChatHistory(emptyList())

            // Simulate file upload and summary generation
            val fileResult = FileParseResult.Success(
                content = "This is the content of the uploaded PDF document.",
                fileName = "test_document.pdf",
                fileType = "PDF",
                wordCount = 9
            )

            // Simulate user message
            val userMessage = ChatMessage(
                message = "📄 Upload file: ${fileResult.fileName}\n\nMohon buatkan ringkasan dari file ini.",
                isUser = true,
                timestamp = System.currentTimeMillis()
            )

            // Simulate AI summary response
            val aiSummary = ChatMessage(
                message = "Ringkasan dokumen:\n\n1. Poin utama pertama\n2. Poin utama kedua\n3. Kesimpulan",
                isUser = false,
                timestamp = System.currentTimeMillis()
            )

            // When - Save to chat history
            val chatHistory = ChatHistory(
                id = "chat_pdf_001",
                categoryId = null,
                categoryName = "Semua Kategori",
                messages = listOf(userMessage, aiSummary).map { it.toSerializable() },
                lastMessagePreview = "Ringkasan dokumen: 1. Poin...",
                timestamp = System.currentTimeMillis(),
                isDeleted = false
            )

            dataStoreManager.addChatHistory(chatHistory)

            // Then - Should be saved and retrievable
            val savedHistories = dataStoreManager.chatHistoryFlow.first()
            assertEquals(1, savedHistories.size)
            assertEquals(2, savedHistories[0].messages.size)

            val messages = savedHistories[0].messages
            assertTrue(messages[0].message.contains("Upload file"))
            assertTrue(messages[0].message.contains("test_document.pdf"))
            assertTrue(messages[1].message.contains("Ringkasan dokumen"))
        }
    }

    @Test
    fun testMultipleFileUploads_shouldTrackAll() {
        runBlocking {
            // Given - Clear existing data
            dataStoreManager.saveChatHistory(emptyList())

            // Multiple file uploads with summaries
            val file1Message = ChatMessage(
                message = "📄 Upload file: document1.pdf\n\nBuatkan ringkasan.",
                isUser = true
            )
            val summary1 = ChatMessage(
                message = "Ringkasan document1: Topik A dan B",
                isUser = false
            )

            val file2Message = ChatMessage(
                message = "📄 Upload file: document2.pdf\n\nBuatkan ringkasan.",
                isUser = true
            )
            val summary2 = ChatMessage(
                message = "Ringkasan document2: Topik C dan D",
                isUser = false
            )

            // When - Save chat with multiple uploads
            val chatHistory = ChatHistory(
                id = "chat_multi_pdf",
                categoryId = null,
                categoryName = "Semua",
                messages = listOf(file1Message, summary1, file2Message, summary2).map { it.toSerializable() },
                lastMessagePreview = "Ringkasan document2...",
                timestamp = System.currentTimeMillis(),
                isDeleted = false
            )

            dataStoreManager.addChatHistory(chatHistory)

            // Then - Should track all uploads
            val savedHistories = dataStoreManager.chatHistoryFlow.first()
            assertEquals(4, savedHistories[0].messages.size)

            val messages = savedHistories[0].messages
            assertTrue(messages[0].message.contains("document1.pdf"))
            assertTrue(messages[2].message.contains("document2.pdf"))
        }
    }

    @Test
    fun testSummaryContent_shouldBeReadable() {
        runBlocking {
            // Given - Clear existing data
            dataStoreManager.saveChatHistory(emptyList())

            // File upload with summary
            val fileContent = """
                Important Meeting Notes
                
                Topics discussed:
                1. Project timeline
                2. Budget allocation
                3. Team assignments
            """.trimIndent()

            val summary = """
                Ringkasan Meeting Notes:
                
                Topik yang dibahas:
                - Timeline proyek
                - Alokasi budget
                - Penugasan tim
            """.trimIndent()

            // When - Save chat history
            val chatHistory = ChatHistory(
                id = "chat_summary_readable",
                categoryId = null,
                categoryName = "Semua",
                messages = listOf(
                    ChatMessage(message = "Upload: meeting_notes.txt", isUser = true).toSerializable(),
                    ChatMessage(message = summary, isUser = false).toSerializable()
                ),
                lastMessagePreview = "Ringkasan Meeting Notes...",
                timestamp = System.currentTimeMillis(),
                isDeleted = false
            )

            dataStoreManager.addChatHistory(chatHistory)

            // Then - Summary should be readable
            val savedHistories = dataStoreManager.chatHistoryFlow.first()
            val savedSummary = savedHistories[0].messages[1].message

            assertTrue(savedSummary.contains("Ringkasan"))
            assertTrue(savedSummary.contains("Timeline proyek"))
        }
    }

    @Test
    fun testFileUploadError_shouldHandleGracefully() {
        runBlocking {
            // Given - Clear existing data
            dataStoreManager.saveChatHistory(emptyList())

            // Error scenario (file too large or unsupported format)
            val errorMessage = "⚠️ Gagal membuat ringkasan: File terlalu besar. Maksimal 10MB"

            // When - Save error in chat
            val chatHistory = ChatHistory(
                id = "chat_error",
                categoryId = null,
                categoryName = "Semua",
                messages = listOf(
                    ChatMessage(message = "Upload file: large_file.pdf", isUser = true).toSerializable(),
                    ChatMessage(message = errorMessage, isUser = false).toSerializable()
                ),
                lastMessagePreview = "⚠️ Gagal membuat ringkasan...",
                timestamp = System.currentTimeMillis(),
                isDeleted = false
            )

            dataStoreManager.addChatHistory(chatHistory)

            // Then - Error should be tracked
            val savedHistories = dataStoreManager.chatHistoryFlow.first()
            assertTrue(savedHistories[0].messages[1].message.contains("Gagal"))
            assertTrue(savedHistories[0].messages[1].message.contains("Maksimal 10MB"))
        }
    }

    @Test
    fun testPDFSummaryFormat_shouldBeStructured() {
        runBlocking {
            // Given - Clear existing data
            dataStoreManager.saveChatHistory(emptyList())

            // Structured PDF summary
            val structuredSummary = """
                # Ringkasan Dokumen
                
                ## Poin Utama
                1. **Introduction**: Overview of the topic
                2. **Main Content**: Detailed discussion
                3. **Conclusion**: Key takeaways
                
                ## Rekomendasi
                Dokumen ini cocok untuk pembelajaran dasar AI.
            """.trimIndent()

            // When - Save summary
            val chatHistory = ChatHistory(
                id = "chat_structured",
                categoryId = null,
                categoryName = "Semua",
                messages = listOf(
                    ChatMessage(message = "Upload: ai_basics.pdf", isUser = true).toSerializable(),
                    ChatMessage(message = structuredSummary, isUser = false).toSerializable()
                ),
                lastMessagePreview = "Ringkasan Dokumen...",
                timestamp = System.currentTimeMillis(),
                isDeleted = false
            )

            dataStoreManager.addChatHistory(chatHistory)

            // Then - Structure should be preserved
            val savedHistories = dataStoreManager.chatHistoryFlow.first()
            val savedSummary = savedHistories[0].messages[1].message

            assertTrue(savedSummary.contains("# Ringkasan Dokumen"))
            assertTrue(savedSummary.contains("## Poin Utama"))
            assertTrue(savedSummary.contains("## Rekomendasi"))
        }
    }

    @Test
    fun testSearchInSummaries_shouldFindKeywords() {
        runBlocking {
            // Given - Clear existing data
            dataStoreManager.saveChatHistory(emptyList())

            // Multiple summaries
            val summaries = listOf(
                ChatHistory(
                    id = "chat_sum1",
                    categoryId = null,
                    categoryName = "Semua",
                    messages = listOf(
                        ChatMessage(message = "Upload: kotlin_guide.pdf", isUser = true).toSerializable(),
                        ChatMessage(message = "Ringkasan: Kotlin adalah bahasa programming modern", isUser = false).toSerializable()
                    ),
                    lastMessagePreview = "Ringkasan: Kotlin adalah...",
                    timestamp = System.currentTimeMillis() - 2000,
                    isDeleted = false
                ),
                ChatHistory(
                    id = "chat_sum2",
                    categoryId = null,
                    categoryName = "Semua",
                    messages = listOf(
                        ChatMessage(message = "Upload: java_basics.pdf", isUser = true).toSerializable(),
                        ChatMessage(message = "Ringkasan: Java adalah bahasa OOP yang populer", isUser = false).toSerializable()
                    ),
                    lastMessagePreview = "Ringkasan: Java adalah...",
                    timestamp = System.currentTimeMillis() - 1000,
                    isDeleted = false
                )
            )

            summaries.forEach { dataStoreManager.addChatHistory(it) }

            // When - Search for "Kotlin"
            val savedHistories = dataStoreManager.chatHistoryFlow.first()
            val searchQuery = "Kotlin"
            val searchResults = savedHistories.filter { history ->
                history.messages.any { msg ->
                    msg.message.contains(searchQuery, ignoreCase = true)
                }
            }

            // Then - Should find Kotlin summary
            assertEquals(1, searchResults.size)
            assertTrue(searchResults[0].messages.any { it.message.contains("Kotlin") })
        }
    }

    @Test
    fun testLongSummary_shouldTruncatePreview() {
        // Given - Very long summary
        val longSummary = "A".repeat(200) + " This is a very long summary that should be truncated in the preview"

        // When - Create preview (max 30 chars)
        val maxLength = 30
        val preview = if (longSummary.length > maxLength) {
            longSummary.take(maxLength).trim() + "..."
        } else {
            longSummary
        }

        // Then - Should be truncated
        assertTrue(preview.length <= maxLength + 3)
        assertTrue(preview.endsWith("..."))
    }

    @Test
    fun testFileMetadata_shouldBePreserved() {
        runBlocking {
            // Given - Clear existing data
            dataStoreManager.saveChatHistory(emptyList())

            // File with metadata
            val fileResult = FileParseResult.Success(
                content = "Sample content for testing metadata preservation",
                fileName = "important_document.pdf",
                fileType = "PDF",
                wordCount = 7
            )

            // When - Save chat with file metadata
            val chatHistory = ChatHistory(
                id = "chat_metadata",
                categoryId = null,
                categoryName = "Semua",
                messages = listOf(
                    ChatMessage(
                        message = "📄 Upload file: ${fileResult.fileName}\n" +
                                "Tipe: ${fileResult.fileType}\n" +
                                "Jumlah kata: ${fileResult.wordCount}",
                        isUser = true
                    ).toSerializable(),
                    ChatMessage(message = "Ringkasan telah dibuat.", isUser = false).toSerializable()
                ),
                lastMessagePreview = "Ringkasan telah dibuat.",
                timestamp = System.currentTimeMillis(),
                isDeleted = false
            )

            dataStoreManager.addChatHistory(chatHistory)

            // Then - Metadata should be preserved
            val savedHistories = dataStoreManager.chatHistoryFlow.first()
            val userMessage = savedHistories[0].messages[0].message

            assertTrue(userMessage.contains("important_document.pdf"))
            assertTrue(userMessage.contains("PDF"))
            assertTrue(userMessage.contains("7"))
        }
    }
}