package com.aletheia.app.ui.reader

import com.aletheia.app.data.SettingsRepository
import org.json.JSONObject

data class ReaderPreferences(
    val fontName: String = DEFAULT_FONT,
    val fontSize: Int = 20,
    val lineHeight: Double = 1.55,
    val margin: Int = 13,
    val textAlign: String = ALIGN_JUSTIFY,
    val theme: String = THEME_LIGHT,
    val verticalScroll: Boolean = false,
    val pageTurnMode: String = PAGE_TURN_TAP_SWIPE,
    val invertZones: Boolean = false,
    val brightnessGesture: Boolean = false,
    val systemBrightness: Boolean = false,
    val brightness: Int = 100,
    val orientation: String = ORIENTATION_AUTO,
    val volumeButtons: Boolean = true,
    val keepScreenOn: Boolean = false,
    val showTitle: Boolean = true,
    val showStatus: Boolean = false
) {
    fun hasSameEnginePreferences(other: ReaderPreferences): Boolean =
        fontName == other.fontName &&
            fontSize == other.fontSize &&
            lineHeight == other.lineHeight &&
            margin == other.margin &&
            textAlign == other.textAlign &&
            theme == other.theme &&
            verticalScroll == other.verticalScroll &&
            pageTurnMode == other.pageTurnMode &&
            invertZones == other.invertZones &&
            brightnessGesture == other.brightnessGesture

    fun toEngineJson(): JSONObject = JSONObject()
        .put("fontFamily", cssFontFamily(fontName))
        .put("fontSize", fontSize.coerceIn(MIN_FONT_SIZE, MAX_FONT_SIZE))
        .put("lineHeight", lineHeight.coerceIn(MIN_LINE_HEIGHT, MAX_LINE_HEIGHT))
        .put("margin", margin.coerceIn(MIN_MARGIN, MAX_MARGIN))
        .put("textAlign", textAlign)
        .put("theme", theme)
        .put("verticalScroll", verticalScroll)
        .put("pageTurnMode", pageTurnMode)
        .put("invertZones", invertZones)
        .put("brightnessGesture", brightnessGesture)

    fun toStateJson(): String = JSONObject()
        .put("fontName", fontName)
        .put("fontSize", fontSize)
        .put("lineHeight", lineHeight)
        .put("margin", margin)
        .put("textAlign", textAlign)
        .put("theme", theme)
        .put("verticalScroll", verticalScroll)
        .put("pageTurnMode", pageTurnMode)
        .put("invertZones", invertZones)
        .put("brightnessGesture", brightnessGesture)
        .put("systemBrightness", systemBrightness)
        .put("brightness", brightness)
        .put("orientation", orientation)
        .put("volumeButtons", volumeButtons)
        .put("keepScreenOn", keepScreenOn)
        .put("showTitle", showTitle)
        .put("showStatus", showStatus)
        .toString()

    fun persist(settings: SettingsRepository) {
        settings.setAll(
            mapOf(
                SettingsRepository.KEY_DEFAULT_FONT_FAMILY to fontName,
                SettingsRepository.KEY_DEFAULT_FONT_SIZE to fontSize.toString(),
                SettingsRepository.KEY_READER_LINE_HEIGHT to lineHeight.toString(),
                SettingsRepository.KEY_READER_MARGIN to margin.toString(),
                SettingsRepository.KEY_READER_ALIGNMENT to textAlign,
                SettingsRepository.KEY_THEME to theme,
                SettingsRepository.KEY_READER_VERTICAL_SCROLL to verticalScroll.toString(),
                SettingsRepository.KEY_READER_PAGE_TURN_MODE to pageTurnMode,
                SettingsRepository.KEY_READER_INVERT_ZONES to invertZones.toString(),
                SettingsRepository.KEY_READER_BRIGHTNESS_GESTURE to brightnessGesture.toString(),
                SettingsRepository.KEY_READER_SYSTEM_BRIGHTNESS to systemBrightness.toString(),
                SettingsRepository.KEY_BRIGHTNESS to brightness.toDouble().toString(),
                SettingsRepository.KEY_READER_ORIENTATION to orientation,
                SettingsRepository.KEY_READER_VOLUME_BUTTONS to volumeButtons.toString(),
                SettingsRepository.KEY_READER_KEEP_SCREEN_ON to keepScreenOn.toString(),
                SettingsRepository.KEY_READER_SHOW_TITLE to showTitle.toString(),
                SettingsRepository.KEY_READER_SHOW_STATUS to showStatus.toString()
            )
        )
    }

    companion object {
        const val THEME_LIGHT = "light"
        const val THEME_SEPIA = "sepia"
        const val THEME_DARK = "dark"
        const val ALIGN_JUSTIFY = "justify"
        const val ALIGN_LEFT = "left"
        const val PAGE_TURN_TAP_SWIPE = "tapSwipe"
        const val PAGE_TURN_SWIPE = "swipe"
        const val PAGE_TURN_TAP = "tap"
        const val ORIENTATION_AUTO = "auto"
        const val ORIENTATION_PORTRAIT = "portrait"
        const val ORIENTATION_LANDSCAPE = "landscape"
        const val DEFAULT_FONT = "Droid Serif"
        const val MIN_FONT_SIZE = 12
        const val MAX_FONT_SIZE = 42
        const val MIN_LINE_HEIGHT = 1.1
        const val MAX_LINE_HEIGHT = 2.4
        const val MIN_MARGIN = 8
        const val MAX_MARGIN = 72

        val FONT_NAMES = listOf(
            "Droid Serif",
            "EB Garamond",
            "Droid Sans",
            "Roboto",
            "PT Sans",
            "PT Serif",
            "Merriweather",
            "Open Sans"
        )

        fun from(settings: SettingsRepository): ReaderPreferences {
            val values = settings.getAll(READER_SETTING_KEYS)
            fun string(key: String, fallback: String = "") = values[key] ?: fallback
            fun int(key: String, fallback: Int) = values[key]?.toIntOrNull() ?: fallback
            fun double(key: String, fallback: Double) = values[key]?.toDoubleOrNull() ?: fallback
            fun boolean(key: String, fallback: Boolean = false) =
                values[key]?.toBooleanStrictOrNull() ?: fallback

            return ReaderPreferences(
                fontName = string(SettingsRepository.KEY_DEFAULT_FONT_FAMILY, DEFAULT_FONT)
                    .takeIf(FONT_NAMES::contains) ?: DEFAULT_FONT,
                fontSize = int(SettingsRepository.KEY_DEFAULT_FONT_SIZE, 20)
                    .coerceIn(MIN_FONT_SIZE, MAX_FONT_SIZE),
                lineHeight = double(SettingsRepository.KEY_READER_LINE_HEIGHT, 1.55)
                    .coerceIn(MIN_LINE_HEIGHT, MAX_LINE_HEIGHT),
                margin = int(SettingsRepository.KEY_READER_MARGIN, 13)
                    .coerceIn(MIN_MARGIN, MAX_MARGIN),
                textAlign = string(SettingsRepository.KEY_READER_ALIGNMENT, ALIGN_JUSTIFY)
                    .takeIf { it == ALIGN_JUSTIFY || it == ALIGN_LEFT } ?: ALIGN_JUSTIFY,
                theme = string(SettingsRepository.KEY_THEME, THEME_LIGHT)
                    .takeIf { it == THEME_LIGHT || it == THEME_SEPIA || it == THEME_DARK }
                    ?: THEME_LIGHT,
                verticalScroll = boolean(SettingsRepository.KEY_READER_VERTICAL_SCROLL),
                pageTurnMode = string(SettingsRepository.KEY_READER_PAGE_TURN_MODE, PAGE_TURN_TAP_SWIPE)
                    .takeIf { it == PAGE_TURN_TAP_SWIPE || it == PAGE_TURN_SWIPE || it == PAGE_TURN_TAP }
                    ?: PAGE_TURN_TAP_SWIPE,
                invertZones = boolean(SettingsRepository.KEY_READER_INVERT_ZONES),
                brightnessGesture = boolean(SettingsRepository.KEY_READER_BRIGHTNESS_GESTURE),
                systemBrightness = boolean(SettingsRepository.KEY_READER_SYSTEM_BRIGHTNESS),
                brightness = double(SettingsRepository.KEY_BRIGHTNESS, 100.0).toInt().coerceIn(10, 100),
                orientation = string(SettingsRepository.KEY_READER_ORIENTATION, ORIENTATION_AUTO)
                    .takeIf { it == ORIENTATION_AUTO || it == ORIENTATION_PORTRAIT || it == ORIENTATION_LANDSCAPE }
                    ?: ORIENTATION_AUTO,
                volumeButtons = boolean(SettingsRepository.KEY_READER_VOLUME_BUTTONS, true),
                keepScreenOn = boolean(SettingsRepository.KEY_READER_KEEP_SCREEN_ON),
                showTitle = boolean(SettingsRepository.KEY_READER_SHOW_TITLE, true),
                showStatus = boolean(SettingsRepository.KEY_READER_SHOW_STATUS)
            )
        }

        fun fromStateJson(raw: String?): ReaderPreferences? {
            if (raw.isNullOrBlank()) return null
            return runCatching {
                val json = JSONObject(raw)
            ReaderPreferences(
                fontName = json.optString("fontName", DEFAULT_FONT)
                    .takeIf(FONT_NAMES::contains) ?: DEFAULT_FONT,
                fontSize = json.optInt("fontSize", 20).coerceIn(MIN_FONT_SIZE, MAX_FONT_SIZE),
                lineHeight = json.optDouble("lineHeight", 1.55)
                    .coerceIn(MIN_LINE_HEIGHT, MAX_LINE_HEIGHT),
                margin = json.optInt("margin", 13).coerceIn(MIN_MARGIN, MAX_MARGIN),
                textAlign = json.optString("textAlign", ALIGN_JUSTIFY)
                    .takeIf { it == ALIGN_JUSTIFY || it == ALIGN_LEFT } ?: ALIGN_JUSTIFY,
                theme = json.optString("theme", THEME_LIGHT)
                    .takeIf { it == THEME_LIGHT || it == THEME_SEPIA || it == THEME_DARK }
                    ?: THEME_LIGHT,
                verticalScroll = json.optBoolean("verticalScroll", false),
                pageTurnMode = json.optString("pageTurnMode", PAGE_TURN_TAP_SWIPE)
                    .takeIf { it == PAGE_TURN_TAP_SWIPE || it == PAGE_TURN_SWIPE || it == PAGE_TURN_TAP }
                    ?: PAGE_TURN_TAP_SWIPE,
                invertZones = json.optBoolean("invertZones", false),
                brightnessGesture = json.optBoolean("brightnessGesture", false),
                systemBrightness = json.optBoolean("systemBrightness", false),
                brightness = json.optInt("brightness", 100).coerceIn(10, 100),
                orientation = json.optString("orientation", ORIENTATION_AUTO)
                    .takeIf { it == ORIENTATION_AUTO || it == ORIENTATION_PORTRAIT || it == ORIENTATION_LANDSCAPE }
                    ?: ORIENTATION_AUTO,
                volumeButtons = json.optBoolean("volumeButtons", true),
                keepScreenOn = json.optBoolean("keepScreenOn", false),
                showTitle = json.optBoolean("showTitle", true),
                showStatus = json.optBoolean("showStatus", false)
                )
            }.getOrNull()
        }

        private fun cssFontFamily(name: String): String = when (name) {
            "EB Garamond" -> "'EB Garamond', Georgia, serif"
            "Droid Sans" -> "'Droid Sans', Roboto, sans-serif"
            "Roboto" -> "Roboto, sans-serif"
            "PT Sans" -> "'PT Sans', Roboto, sans-serif"
            "PT Serif" -> "'PT Serif', 'Noto Serif', serif"
            "Merriweather" -> "Merriweather, 'Noto Serif', serif"
            "Open Sans" -> "'Open Sans', Roboto, sans-serif"
            else -> "'Droid Serif', 'Noto Serif', serif"
        }

        private val READER_SETTING_KEYS = listOf(
            SettingsRepository.KEY_DEFAULT_FONT_FAMILY,
            SettingsRepository.KEY_DEFAULT_FONT_SIZE,
            SettingsRepository.KEY_READER_LINE_HEIGHT,
            SettingsRepository.KEY_READER_MARGIN,
            SettingsRepository.KEY_READER_ALIGNMENT,
            SettingsRepository.KEY_THEME,
            SettingsRepository.KEY_READER_VERTICAL_SCROLL,
            SettingsRepository.KEY_READER_PAGE_TURN_MODE,
            SettingsRepository.KEY_READER_INVERT_ZONES,
            SettingsRepository.KEY_READER_BRIGHTNESS_GESTURE,
            SettingsRepository.KEY_READER_SYSTEM_BRIGHTNESS,
            SettingsRepository.KEY_BRIGHTNESS,
            SettingsRepository.KEY_READER_ORIENTATION,
            SettingsRepository.KEY_READER_VOLUME_BUTTONS,
            SettingsRepository.KEY_READER_KEEP_SCREEN_ON,
            SettingsRepository.KEY_READER_SHOW_TITLE,
            SettingsRepository.KEY_READER_SHOW_STATUS
        )
    }
}
