package com.tt.honeyDue.ui.screens

import com.tt.honeyDue.viewmodel.NotificationCategoriesController
import com.tt.honeyDue.viewmodel.NotificationCategoryKeys
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue

/**
 * P4 Stream P — state-logic tests for the per-category notification UI.
 *
 * These mirror the iOS per-category toggles in
 * `iosApp/iosApp/Profile/NotificationPreferencesView.swift` and exercise
 * [NotificationCategoriesController] — a commonMain façade used by
 * [NotificationPreferencesScreen] that delegates persistence to the
 * Android DataStore-backed `NotificationPreferencesStore` in production
 * and to a fake in these tests.
 *
 * We use plain kotlin.test here (no Compose UI testing) for the same
 * reasons noted in ThemeSelectionScreenTest / FeatureComparisonScreenTest
 * — the commonTest recomposer+Dispatchers interplay is flaky on
 * iosSimulator.
 */
@OptIn(ExperimentalCoroutinesApi::class)
class NotificationPreferencesScreenTest {

    /** In-memory stand-in for NotificationPreferencesStore. */
    private class FakeStore(
        initial: Map<String, Boolean> = NotificationCategoryKeys.ALL.associateWith { true },
    ) {
        val state = initial.toMutableMap()
        val setCategoryCalls: MutableList<Pair<String, Boolean>> = mutableListOf()
        val setAllCalls: MutableList<Boolean> = mutableListOf()

        suspend fun setCategoryEnabled(id: String, enabled: Boolean) {
            setCategoryCalls += (id to enabled)
            state[id] = enabled
        }

        suspend fun setAllEnabled(enabled: Boolean) {
            setAllCalls += enabled
            NotificationCategoryKeys.ALL.forEach { state[it] = enabled }
        }

        suspend fun loadAll(): Map<String, Boolean> =
            NotificationCategoryKeys.ALL.associateWith { state[it] ?: true }
    }

    private fun controllerFor(store: FakeStore) = NotificationCategoriesController(
        loadAll = { store.loadAll() },
        setCategory = { id, v -> store.setCategoryEnabled(id, v) },
        setAll = { v -> store.setAllEnabled(v) },
    )

    @Test
    fun categoryKeys_matchNotificationChannels() {
        // Parity guard: if NotificationChannels ever adds/removes a channel,
        // the category keys used by this screen must update in lockstep.
        assertEquals(
            listOf("task_reminder", "task_overdue", "residence_invite", "subscription"),
            NotificationCategoryKeys.ALL,
        )
    }

    @Test
    fun initialState_loadsAllCategoriesEnabled() = runTest {
        val store = FakeStore()
        val controller = controllerFor(store)
        val snapshot = controller.load()

        assertEquals(4, snapshot.size)
        snapshot.values.forEach { assertTrue(it, "Every category starts enabled") }
    }

    @Test
    fun toggleCategory_invokesSetCategoryEnabled() = runTest {
        val store = FakeStore()
        val controller = controllerFor(store)

        controller.onCategoryToggle("task_reminder", false)

        assertEquals(1, store.setCategoryCalls.size)
        assertEquals("task_reminder" to false, store.setCategoryCalls[0])
        assertFalse(store.state["task_reminder"]!!)
    }

    @Test
    fun toggleDifferentCategories_isolatesUpdates() = runTest {
        val store = FakeStore()
        val controller = controllerFor(store)

        controller.onCategoryToggle("task_overdue", false)
        controller.onCategoryToggle("subscription", false)

        assertFalse(store.state["task_overdue"]!!)
        assertFalse(store.state["subscription"]!!)
        // Untouched categories remain enabled
        assertTrue(store.state["task_reminder"]!!)
        assertTrue(store.state["residence_invite"]!!)
    }

    @Test
    fun masterToggle_off_invokesSetAllEnabledFalse() = runTest {
        val store = FakeStore()
        val controller = controllerFor(store)

        controller.onMasterToggle(false)

        assertEquals(listOf(false), store.setAllCalls)
        assertFalse(store.state["task_reminder"]!!)
        assertFalse(store.state["task_overdue"]!!)
        assertFalse(store.state["residence_invite"]!!)
        assertFalse(store.state["subscription"]!!)
    }

    @Test
    fun masterToggle_on_reenablesAllCategories() = runTest {
        val store = FakeStore(
            initial = mapOf(
                "task_reminder" to false,
                "task_overdue" to false,
                "residence_invite" to false,
                "subscription" to false,
            ),
        )
        val controller = controllerFor(store)

        controller.onMasterToggle(true)

        assertEquals(listOf(true), store.setAllCalls)
        NotificationCategoryKeys.ALL.forEach { id ->
            assertTrue(store.state[id]!!, "Category $id should be re-enabled")
        }
    }

    @Test
    fun computeMasterState_trueWhenAllEnabled_falseOtherwise() {
        val allOn = mapOf(
            "task_reminder" to true,
            "task_overdue" to true,
            "residence_invite" to true,
            "subscription" to true,
        )
        val oneOff = allOn.toMutableMap().apply { put("task_overdue", false) }

        assertTrue(NotificationCategoriesController.computeMasterState(allOn))
        assertFalse(NotificationCategoriesController.computeMasterState(oneOff))
        assertFalse(NotificationCategoriesController.computeMasterState(emptyMap()))
    }
}
