package com.tt.honeyDue.ui.screens.theme

import com.tt.honeyDue.ui.theme.AppThemes
import com.tt.honeyDue.ui.theme.ThemeManager
import kotlin.test.AfterTest
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertNotSame
import kotlin.test.assertSame
import kotlin.test.assertTrue

/**
 * P2 Stream D — ThemeSelectionScreen tests.
 *
 * These tests exercise the state-logic backing the screen. We intentionally
 * use plain `kotlin.test` rather than `runComposeUiTest { }` because
 * Compose UI testing in commonTest for a KMP project with `ThemeManager`
 * (which uses `mutableStateOf` and a platform-backed `ThemeStorage`) is
 * flaky — the recomposer / Dispatchers interplay breaks on iosSimulator.
 *
 * Instead we assert the public contract the screen relies on:
 *   - The 11 iOS themes are exposed by `ThemeManager.getAllThemes()` with
 *     the IDs and display names the row-cards render.
 *   - Tapping a row updates `ThemeManager.currentTheme` to the tapped id.
 *   - The "live header preview" simply reads `ThemeManager.currentTheme`,
 *     so selecting a theme advances that reactive value.
 *   - "Initially selected" is whatever `ThemeManager.currentTheme` returns
 *     at composition time — asserted by comparing ids.
 *
 * Mirrors iOS `iosApp/iosApp/Profile/ThemeSelectionView.swift`.
 */
class ThemeSelectionScreenTest {

    private lateinit var originalThemeId: String

    @BeforeTest
    fun rememberOriginalTheme() {
        originalThemeId = ThemeManager.currentTheme.id
    }

    @AfterTest
    fun restoreOriginalTheme() {
        ThemeManager.setTheme(originalThemeId)
    }

    // 1. Renders 11 theme cards with correct names and IDs.
    @Test
    fun allElevenThemesAreAvailableForTheScreen() {
        val themes = ThemeManager.getAllThemes()
        assertEquals(11, themes.size, "ThemeSelectionScreen must offer all 11 iOS themes")

        val expectedIds = listOf(
            "default", "teal", "ocean", "forest", "sunset", "monochrome",
            "lavender", "crimson", "midnight", "desert", "mint"
        )
        assertEquals(expectedIds, themes.map { it.id })

        // Each theme must have a non-blank displayName and description
        themes.forEach { theme ->
            assertTrue(theme.displayName.isNotBlank(), "${theme.id} needs displayName")
            assertTrue(theme.description.isNotBlank(), "${theme.id} needs description")
        }
    }

    // 2. Initially-selected theme matches ThemeManager.currentTheme.
    @Test
    fun initiallySelectedThemeReflectsThemeManager() {
        ThemeManager.setTheme("ocean")
        val selectedId = ThemeManager.currentTheme.id
        assertEquals("ocean", selectedId, "Screen shows whatever ThemeManager reports as current")

        // The card for that id is the one that renders the checkmark.
        val oceanTheme = ThemeManager.getAllThemes().single { it.id == selectedId }
        assertEquals("Ocean", oceanTheme.displayName)
    }

    // 3. Tapping a theme card changes ThemeManager.currentTheme to the tapped id.
    @Test
    fun tappingThemeCardUpdatesCurrentTheme() {
        ThemeManager.setTheme("default")
        assertEquals("default", ThemeManager.currentTheme.id)

        // Simulate the screen's onThemeSelected callback.
        ThemeSelectionScreenState.onThemeTap("crimson")

        assertEquals("crimson", ThemeManager.currentTheme.id)
        assertSame(AppThemes.Crimson, ThemeManager.currentTheme)
    }

    // 4. Live preview header reflects the selected theme's primary color.
    //    The preview reads `ThemeManager.currentTheme.lightPrimary` (or dark).
    @Test
    fun livePreviewTracksSelectedThemePrimaryColor() {
        ThemeManager.setTheme("default")
        val defaultPrimary = ThemeManager.currentTheme.lightPrimary

        ThemeSelectionScreenState.onThemeTap("forest")
        val forestPrimary = ThemeManager.currentTheme.lightPrimary

        assertNotNull(forestPrimary)
        assertNotSame(defaultPrimary, forestPrimary, "Primary color must update on theme tap")
        assertEquals(AppThemes.Forest.lightPrimary, forestPrimary)
    }

    // 5. The screen's back-navigation callback is invoked when the user
    //    confirms. Verified by the state helper recording the call.
    @Test
    fun onConfirmNavigatesBack() {
        var navigatedBack = false
        ThemeSelectionScreenState.onConfirm(onBack = { navigatedBack = true })
        assertTrue(navigatedBack, "Confirm/Done must call the back-navigation callback")
    }

    // 6. Tapping every theme in turn leaves currentTheme at the last tap —
    //    proves the reactive state machine across a full cycle.
    @Test
    fun stateSelectionFlowCyclesThroughAllThemes() {
        val ids = ThemeManager.getAllThemes().map { it.id }
        ids.forEach { id ->
            ThemeSelectionScreenState.onThemeTap(id)
            assertEquals(id, ThemeManager.currentTheme.id)
        }
    }
}
