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.Category
import com.example.notesai.data.model.Note
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 Trash Functionality
 * Coverage:
 * - TC-03: Soft delete → restore dari trash
 */
@RunWith(AndroidJUnit4::class)
class TrashFunctionalityTest {

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

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

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

        dataStoreManager = DataStoreManager(context)
    }

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

    // ================== TC-03: SOFT DELETE & RESTORE ==================

    @Test
    fun testSoftDeleteNote_shouldMarkAsDeleted() = runBlocking {
        // Given - Create a note
        val note = Note(
            id = "note_001",
            categoryId = "cat_001",
            title = "Important Note",
            content = "This is important content",
            timestamp = System.currentTimeMillis(),
            isDeleted = false
        )

        dataStoreManager.saveNotes(listOf(note))

        // When - Soft delete the note
        val deletedNote = note.copy(isDeleted = true)
        dataStoreManager.saveNotes(listOf(deletedNote))

        // Then - Note should be marked as deleted
        val savedNotes = dataStoreManager.notesFlow.first()
        assertEquals(1, savedNotes.size)
        assertTrue(savedNotes[0].isDeleted)
        assertEquals("Important Note", savedNotes[0].title)
    }

    @Test
    fun testRestoreNoteFromTrash_shouldUnmarkDeleted() = runBlocking {
        // Given - A deleted note
        val deletedNote = Note(
            id = "note_001",
            categoryId = "cat_001",
            title = "Deleted Note",
            content = "This was deleted",
            timestamp = System.currentTimeMillis(),
            isDeleted = true
        )

        dataStoreManager.saveNotes(listOf(deletedNote))

        // When - Restore the note
        val restoredNote = deletedNote.copy(isDeleted = false)
        dataStoreManager.saveNotes(listOf(restoredNote))

        // Then - Note should be restored
        val savedNotes = dataStoreManager.notesFlow.first()
        assertEquals(1, savedNotes.size)
        assertFalse(savedNotes[0].isDeleted)
        assertEquals("Deleted Note", savedNotes[0].title)
    }

    @Test
    fun testSoftDeleteCategory_shouldMarkAsDeleted() = runBlocking {
        // Given - Create a category
        val category = Category(
            id = "cat_001",
            name = "Work",
            gradientStart = 0xFFE91E63,
            gradientEnd = 0xFF9C27B0,
            timestamp = System.currentTimeMillis(),
            isDeleted = false
        )

        dataStoreManager.saveCategories(listOf(category))

        // When - Soft delete the category
        val deletedCategory = category.copy(isDeleted = true)
        dataStoreManager.saveCategories(listOf(deletedCategory))

        // Then - Category should be marked as deleted
        val savedCategories = dataStoreManager.categoriesFlow.first()
        assertEquals(1, savedCategories.size)
        assertTrue(savedCategories[0].isDeleted)
        assertEquals("Work", savedCategories[0].name)
    }

    @Test
    fun testRestoreCategoryFromTrash_shouldUnmarkDeleted() = runBlocking {
        // Given - A deleted category
        val deletedCategory = Category(
            id = "cat_001",
            name = "Personal",
            gradientStart = 0xFF2196F3,
            gradientEnd = 0xFF03A9F4,
            timestamp = System.currentTimeMillis(),
            isDeleted = true
        )

        dataStoreManager.saveCategories(listOf(deletedCategory))

        // When - Restore the category
        val restoredCategory = deletedCategory.copy(isDeleted = false)
        dataStoreManager.saveCategories(listOf(restoredCategory))

        // Then - Category should be restored
        val savedCategories = dataStoreManager.categoriesFlow.first()
        assertEquals(1, savedCategories.size)
        assertFalse(savedCategories[0].isDeleted)
        assertEquals("Personal", savedCategories[0].name)
    }

    @Test
    fun testFilterDeletedNotes_shouldOnlyShowDeleted() = runBlocking {
        // Given - Mix of deleted and active notes
        val notes = listOf(
            Note(id = "note_001", categoryId = "cat_001", title = "Active 1", isDeleted = false),
            Note(id = "note_002", categoryId = "cat_001", title = "Deleted 1", isDeleted = true),
            Note(id = "note_003", categoryId = "cat_001", title = "Active 2", isDeleted = false),
            Note(id = "note_004", categoryId = "cat_001", title = "Deleted 2", isDeleted = true),
            Note(id = "note_005", categoryId = "cat_001", title = "Active 3", isDeleted = false)
        )

        dataStoreManager.saveNotes(notes)

        // When - Filter only deleted notes (simulating TrashScreen behavior)
        val savedNotes = dataStoreManager.notesFlow.first()
        val deletedNotes = savedNotes.filter { it.isDeleted }

        // Then - Should only have 2 deleted notes
        assertEquals(2, deletedNotes.size)
        assertTrue(deletedNotes.all { it.isDeleted })
        assertEquals(setOf("Deleted 1", "Deleted 2"), deletedNotes.map { it.title }.toSet())
    }

    @Test
    fun testFilterDeletedCategories_shouldOnlyShowDeleted() = runBlocking {
        // Given - Mix of deleted and active categories
        val categories = listOf(
            Category(id = "cat_001", name = "Active Work", gradientStart = 0xFF000000, gradientEnd = 0xFF111111, isDeleted = false),
            Category(id = "cat_002", name = "Deleted Personal", gradientStart = 0xFF222222, gradientEnd = 0xFF333333, isDeleted = true),
            Category(id = "cat_003", name = "Active Ideas", gradientStart = 0xFF444444, gradientEnd = 0xFF555555, isDeleted = false),
            Category(id = "cat_004", name = "Deleted Projects", gradientStart = 0xFF666666, gradientEnd = 0xFF777777, isDeleted = true)
        )

        dataStoreManager.saveCategories(categories)

        // When - Filter only deleted categories
        val savedCategories = dataStoreManager.categoriesFlow.first()
        val deletedCategories = savedCategories.filter { it.isDeleted }

        // Then - Should only have 2 deleted categories
        assertEquals(2, deletedCategories.size)
        assertTrue(deletedCategories.all { it.isDeleted })
        assertEquals(setOf("Deleted Personal", "Deleted Projects"), deletedCategories.map { it.name }.toSet())
    }

    @Test
    fun testPermanentDeleteNote_shouldRemoveCompletely() = runBlocking {
        // Given - Two deleted notes
        val notes = listOf(
            Note(id = "note_001", categoryId = "cat_001", title = "Keep This", isDeleted = true),
            Note(id = "note_002", categoryId = "cat_001", title = "Delete This", isDeleted = true)
        )

        dataStoreManager.saveNotes(notes)

        // When - Permanently delete one note (remove from list)
        val remainingNotes = notes.filter { it.id != "note_002" }
        dataStoreManager.saveNotes(remainingNotes)

        // Then - Should only have 1 note left
        val savedNotes = dataStoreManager.notesFlow.first()
        assertEquals(1, savedNotes.size)
        assertEquals("Keep This", savedNotes[0].title)
    }

    @Test
    fun testPermanentDeleteCategory_shouldRemoveCompletely() = runBlocking {
        // Given - Two deleted categories
        val categories = listOf(
            Category(id = "cat_001", name = "Keep This", gradientStart = 0xFF000000, gradientEnd = 0xFF111111, isDeleted = true),
            Category(id = "cat_002", name = "Delete This", gradientStart = 0xFF222222, gradientEnd = 0xFF333333, isDeleted = true)
        )

        dataStoreManager.saveCategories(categories)

        // When - Permanently delete one category
        val remainingCategories = categories.filter { it.id != "cat_002" }
        dataStoreManager.saveCategories(remainingCategories)

        // Then - Should only have 1 category left
        val savedCategories = dataStoreManager.categoriesFlow.first()
        assertEquals(1, savedCategories.size)
        assertEquals("Keep This", savedCategories[0].name)
    }

    @Test
    fun testSearchInTrash_shouldFindDeletedItems() = runBlocking {
        // Given - Deleted notes with different content
        val notes = listOf(
            Note(id = "note_001", categoryId = "cat_001", title = "Meeting Minutes", content = "Discuss Q4 goals", isDeleted = true),
            Note(id = "note_002", categoryId = "cat_001", title = "Shopping List", content = "Buy groceries", isDeleted = true),
            Note(id = "note_003", categoryId = "cat_001", title = "Project Ideas", content = "Brainstorm features", isDeleted = true)
        )

        dataStoreManager.saveNotes(notes)

        // When - Search for "Meeting" (simulating TrashScreen search)
        val savedNotes = dataStoreManager.notesFlow.first()
        val deletedNotes = savedNotes.filter { it.isDeleted }
        val searchQuery = "Meeting"
        val searchResults = deletedNotes.filter {
            it.title.contains(searchQuery, ignoreCase = true) ||
                    it.content.contains(searchQuery, ignoreCase = true)
        }

        // Then - Should find 1 note
        assertEquals(1, searchResults.size)
        assertEquals("Meeting Minutes", searchResults[0].title)
    }

    @Test
    fun testRestoreMultipleNotes_shouldRestoreAll() = runBlocking {
        // Given - Multiple deleted notes
        val notes = listOf(
            Note(id = "note_001", categoryId = "cat_001", title = "Note 1", isDeleted = true),
            Note(id = "note_002", categoryId = "cat_001", title = "Note 2", isDeleted = true),
            Note(id = "note_003", categoryId = "cat_001", title = "Note 3", isDeleted = true)
        )

        dataStoreManager.saveNotes(notes)

        // When - Restore all notes
        val restoredNotes = notes.map { it.copy(isDeleted = false) }
        dataStoreManager.saveNotes(restoredNotes)

        // Then - All notes should be restored
        val savedNotes = dataStoreManager.notesFlow.first()
        assertEquals(3, savedNotes.size)
        assertTrue(savedNotes.all { !it.isDeleted })
    }

    @Test
    fun testDeletedNotePreservesAllData_shouldKeepContent() = runBlocking {
        // Given - A note with all fields populated
        val note = Note(
            id = "note_001",
            categoryId = "cat_001",
            title = "Complete Note",
            description = "This is a description",
            content = "Full content here with details",
            timestamp = System.currentTimeMillis(),
            isPinned = true,
            isArchived = false,
            isDeleted = false
        )

        dataStoreManager.saveNotes(listOf(note))

        // When - Soft delete
        val deletedNote = note.copy(isDeleted = true)
        dataStoreManager.saveNotes(listOf(deletedNote))

        // Then - All data should be preserved
        val savedNotes = dataStoreManager.notesFlow.first()
        assertEquals(1, savedNotes.size)
        with(savedNotes[0]) {
            assertEquals("Complete Note", title)
            assertEquals("This is a description", description)
            assertEquals("Full content here with details", content)
            assertTrue(isPinned)
            assertFalse(isArchived)
            assertTrue(isDeleted)
        }
    }
}