package com.aletheia.app.ui.reader

import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test

class ReaderEventTest {
    @Test
    fun progressPreservesStructuredLocator() {
        val event = ReaderEvent.parse(
            """
            {
              "version": 2,
              "type": "progress",
              "payload": {
                "progress": 0.42,
                "locator": {"type":"epub","cfi":"epubcfi(/6/2)"},
                "chapter": "Глава 2",
                "currentPage": 12,
                "totalPages": 30,
                "chapterCurrentPage": 2,
                "chapterTotalPages": 7
              }
            }
            """.trimIndent()
        ) as ReaderEvent.Progress

        assertEquals(0.42, event.progress, 0.0001)
        assertEquals("Глава 2", event.chapter)
        assertTrue(requireNotNull(event.locator).contains("epubcfi(/6/2)"))
        assertEquals(12, event.currentPage)
        assertEquals(7, event.chapterTotalPages)
    }

    @Test
    fun tocReadsV2ItemsArray() {
        val event = ReaderEvent.parse(
            """
            {
              "version": 2,
              "type": "toc",
              "payload": {
                "items": [
                  {"label":"Глава 1","href":"chapter-1","depth":0},
                  {"label":"Часть 1","href":"part-1","depth":1}
                ]
              }
            }
            """.trimIndent()
        ) as ReaderEvent.Toc

        assertEquals(2, event.chapters.size)
        assertEquals("Часть 1", event.chapters[1].label)
        assertEquals(1, event.chapters[1].depth)
    }

    @Test
    fun progressAcceptsEngineChapterPageAliases() {
        val event = ReaderEvent.parse(
            """
            {
              "version": 2,
              "type": "progress",
              "payload": {
                "progress": 0.5,
                "chapterPage": 4,
                "chapterTotal": 11
              }
            }
            """.trimIndent()
        ) as ReaderEvent.Progress

        assertEquals(4, event.chapterCurrentPage)
        assertEquals(11, event.chapterTotalPages)
    }

    @Test
    fun errorPreservesRecoveryMetadata() {
        val event = ReaderEvent.parse(
            """
            {
              "version": 2,
              "type": "error",
              "payload": {
                "stage": "epub.navigation",
                "code": "DisplayError",
                "message": "Не удалось перейти",
                "recoverable": false
              }
            }
            """.trimIndent()
        ) as ReaderEvent.Error

        assertEquals("epub.navigation", event.stage)
        assertEquals("DisplayError", event.code)
        assertEquals("Не удалось перейти", event.message)
        assertEquals(false, event.recoverable)
    }

    @Test
    fun preferencesUseReaderV2Schema() {
        val json = ReaderPreferences(
            fontName = "PT Serif",
            fontSize = 24,
            lineHeight = 1.7,
            margin = 20,
            verticalScroll = true,
            invertZones = true
        ).toEngineJson()

        assertEquals(24, json.getInt("fontSize"))
        assertEquals(1.7, json.getDouble("lineHeight"), 0.0001)
        assertTrue(json.getString("fontFamily").contains("PT Serif"))
        assertTrue(json.getBoolean("verticalScroll"))
        assertTrue(json.getBoolean("invertZones"))
    }

    @Test
    fun preferencesClampValuesToReaderV2Contract() {
        val json = ReaderPreferences(
            fontSize = 100,
            lineHeight = 0.5,
            margin = 2
        ).toEngineJson()

        assertEquals(ReaderPreferences.MAX_FONT_SIZE, json.getInt("fontSize"))
        assertEquals(ReaderPreferences.MIN_LINE_HEIGHT, json.getDouble("lineHeight"), 0.0001)
        assertEquals(ReaderPreferences.MIN_MARGIN, json.getInt("margin"))
    }

    @Test
    fun preferencesStateRoundTripPreservesNativeOptions() {
        val source = ReaderPreferences(
            fontName = "Merriweather",
            fontSize = 26,
            lineHeight = 1.8,
            margin = 32,
            theme = ReaderPreferences.THEME_DARK,
            verticalScroll = true,
            brightness = 63,
            orientation = ReaderPreferences.ORIENTATION_LANDSCAPE,
            keepScreenOn = true,
            showTitle = false,
            showStatus = true
        )

        assertEquals(source, ReaderPreferences.fromStateJson(source.toStateJson()))
    }

    @Test
    fun nativeOnlyPreferencesDoNotInvalidateWebEngine() {
        val source = ReaderPreferences()
        val nativeOnly = source.copy(
            brightness = 42,
            systemBrightness = true,
            orientation = ReaderPreferences.ORIENTATION_LANDSCAPE,
            volumeButtons = false,
            keepScreenOn = true,
            showTitle = false,
            showStatus = true
        )

        assertTrue(source.hasSameEnginePreferences(nativeOnly))
        assertFalse(source.hasSameEnginePreferences(source.copy(pageTurnMode = ReaderPreferences.PAGE_TURN_SWIPE)))
    }

    @Test
    fun locatorValidationRejectsWrongFormatAndKeepsLegacyFb2() {
        val epubLocator = """{"type":"epub","cfi":"epubcfi(/6/2)"}"""
        val fb2Locator = """{"type":"fb2","sectionId":"fb2-section-2","offset":17}"""
        val legacyFb2Locator = "fb2:fb2-section-2:17:23"

        assertEquals(null, ReaderWebController.validatedLocator("fb2", epubLocator))
        assertEquals(null, ReaderWebController.validatedLocator("epub", fb2Locator))
        assertTrue(requireNotNull(ReaderWebController.validatedLocator("fb2", fb2Locator)).contains("fb2-section-2"))
        assertEquals(legacyFb2Locator, ReaderWebController.validatedLocator("fb2", legacyFb2Locator))
    }
}
