"""Color-scheme helpers for the `topovec view` Qt desktop app."""

from __future__ import annotations

from dataclasses import dataclass

from PySide6 import QtCore, QtGui, QtWidgets


THEME_MODE_SYSTEM = "system"
THEME_MODE_DARK = "dark"
THEME_MODE_LIGHT = "light"
THEME_MODES = (THEME_MODE_SYSTEM, THEME_MODE_DARK, THEME_MODE_LIGHT)
THEME_SETTING_KEY = "ui_theme"


@dataclass(frozen=True)
class ThemeSpec:
    mode: str
    color_scheme: QtCore.Qt.ColorScheme
    viewport_clear_rgba: tuple[float, float, float, float]
    reset_enabled: QtGui.QColor
    reset_active: QtGui.QColor
    reset_disabled: QtGui.QColor
    reset_background_enabled: str
    reset_background_hover: str
    reset_border_enabled: str
    reset_border_hover: str


def _palette_dark() -> QtGui.QPalette:
    palette = QtGui.QPalette()
    colors = {
        QtGui.QPalette.ColorRole.Window: QtGui.QColor("#1f1f1f"),
        QtGui.QPalette.ColorRole.WindowText: QtGui.QColor("#cccccc"),
        QtGui.QPalette.ColorRole.Base: QtGui.QColor("#181818"),
        QtGui.QPalette.ColorRole.AlternateBase: QtGui.QColor("#252526"),
        QtGui.QPalette.ColorRole.ToolTipBase: QtGui.QColor("#252526"),
        QtGui.QPalette.ColorRole.ToolTipText: QtGui.QColor("#cccccc"),
        QtGui.QPalette.ColorRole.Text: QtGui.QColor("#d4d4d4"),
        QtGui.QPalette.ColorRole.Button: QtGui.QColor("#2d2d30"),
        QtGui.QPalette.ColorRole.ButtonText: QtGui.QColor("#d4d4d4"),
        QtGui.QPalette.ColorRole.BrightText: QtGui.QColor("#ffffff"),
        QtGui.QPalette.ColorRole.Highlight: QtGui.QColor("#264f78"),
        QtGui.QPalette.ColorRole.HighlightedText: QtGui.QColor("#ffffff"),
        QtGui.QPalette.ColorRole.PlaceholderText: QtGui.QColor("#7f848e"),
        QtGui.QPalette.ColorRole.Link: QtGui.QColor("#3794ff"),
        QtGui.QPalette.ColorRole.LinkVisited: QtGui.QColor("#4fc1ff"),
    }
    for role, color in colors.items():
        palette.setColor(role, color)
    palette.setColor(
        QtGui.QPalette.ColorGroup.Disabled,
        QtGui.QPalette.ColorRole.Text,
        QtGui.QColor("#7f848e"),
    )
    palette.setColor(
        QtGui.QPalette.ColorGroup.Disabled,
        QtGui.QPalette.ColorRole.ButtonText,
        QtGui.QColor("#7f848e"),
    )
    palette.setColor(
        QtGui.QPalette.ColorGroup.Disabled,
        QtGui.QPalette.ColorRole.WindowText,
        QtGui.QColor("#9da1a8"),
    )
    return palette


def _palette_light() -> QtGui.QPalette:
    palette = QtGui.QPalette()
    colors = {
        QtGui.QPalette.ColorRole.Window: QtGui.QColor("#f5f7fb"),
        QtGui.QPalette.ColorRole.WindowText: QtGui.QColor("#252526"),
        QtGui.QPalette.ColorRole.Base: QtGui.QColor("#ffffff"),
        QtGui.QPalette.ColorRole.AlternateBase: QtGui.QColor("#eef1f6"),
        QtGui.QPalette.ColorRole.ToolTipBase: QtGui.QColor("#ffffff"),
        QtGui.QPalette.ColorRole.ToolTipText: QtGui.QColor("#252526"),
        QtGui.QPalette.ColorRole.Text: QtGui.QColor("#252526"),
        QtGui.QPalette.ColorRole.Button: QtGui.QColor("#edf1f7"),
        QtGui.QPalette.ColorRole.ButtonText: QtGui.QColor("#252526"),
        QtGui.QPalette.ColorRole.BrightText: QtGui.QColor("#ffffff"),
        QtGui.QPalette.ColorRole.Highlight: QtGui.QColor("#cce8ff"),
        QtGui.QPalette.ColorRole.HighlightedText: QtGui.QColor("#0f1720"),
        QtGui.QPalette.ColorRole.PlaceholderText: QtGui.QColor("#7b8591"),
        QtGui.QPalette.ColorRole.Link: QtGui.QColor("#006ab1"),
        QtGui.QPalette.ColorRole.LinkVisited: QtGui.QColor("#0e639c"),
    }
    for role, color in colors.items():
        palette.setColor(role, color)
    palette.setColor(
        QtGui.QPalette.ColorGroup.Disabled,
        QtGui.QPalette.ColorRole.Text,
        QtGui.QColor("#8a929e"),
    )
    palette.setColor(
        QtGui.QPalette.ColorGroup.Disabled,
        QtGui.QPalette.ColorRole.ButtonText,
        QtGui.QColor("#8a929e"),
    )
    palette.setColor(
        QtGui.QPalette.ColorGroup.Disabled,
        QtGui.QPalette.ColorRole.WindowText,
        QtGui.QColor("#8a929e"),
    )
    return palette


_DARK_SPEC = ThemeSpec(
    mode=THEME_MODE_DARK,
    color_scheme=QtCore.Qt.ColorScheme.Dark,
    viewport_clear_rgba=(0.028, 0.03, 0.035, 1.0),
    reset_enabled=QtGui.QColor("#d8b26e"),
    reset_active=QtGui.QColor("#f0c880"),
    reset_disabled=QtGui.QColor("#596270"),
    reset_background_enabled="rgba(216, 178, 110, 0.18)",
    reset_background_hover="rgba(216, 178, 110, 0.28)",
    reset_border_enabled="rgba(216, 178, 110, 0.32)",
    reset_border_hover="rgba(216, 178, 110, 0.48)",
)

_LIGHT_SPEC = ThemeSpec(
    mode=THEME_MODE_LIGHT,
    color_scheme=QtCore.Qt.ColorScheme.Light,
    viewport_clear_rgba=(0.961, 0.969, 0.984, 1.0),
    reset_enabled=QtGui.QColor("#b0751c"),
    reset_active=QtGui.QColor("#c8892e"),
    reset_disabled=QtGui.QColor("#97a3b0"),
    reset_background_enabled="rgba(200, 137, 46, 0.12)",
    reset_background_hover="rgba(200, 137, 46, 0.2)",
    reset_border_enabled="rgba(176, 117, 28, 0.24)",
    reset_border_hover="rgba(176, 117, 28, 0.36)",
)


def normalize_theme_mode(value: object) -> str:
    text = str(value or THEME_MODE_SYSTEM).strip().lower()
    if text not in THEME_MODES:
        return THEME_MODE_SYSTEM
    return text


def system_color_scheme(app: QtWidgets.QApplication) -> QtCore.Qt.ColorScheme:
    style_hints = app.styleHints()
    scheme = style_hints.colorScheme()
    if scheme == QtCore.Qt.ColorScheme.Unknown:
        palette = app.style().standardPalette()
        return (
            QtCore.Qt.ColorScheme.Dark
            if palette.color(QtGui.QPalette.ColorRole.Window).lightnessF() < 0.5
            else QtCore.Qt.ColorScheme.Light
        )
    return scheme


def theme_spec_for_mode(
    mode: str,
    app: QtWidgets.QApplication,
) -> ThemeSpec:
    normalized = normalize_theme_mode(mode)
    if normalized == THEME_MODE_DARK:
        return _DARK_SPEC
    if normalized == THEME_MODE_LIGHT:
        return _LIGHT_SPEC
    return _DARK_SPEC if system_color_scheme(app) == QtCore.Qt.ColorScheme.Dark else _LIGHT_SPEC


def palette_for_mode(
    mode: str,
    app: QtWidgets.QApplication,
) -> QtGui.QPalette | None:
    normalized = normalize_theme_mode(mode)
    if normalized == THEME_MODE_SYSTEM:
        return None
    return _palette_dark() if normalized == THEME_MODE_DARK else _palette_light()


def apply_theme_mode(
    app: QtWidgets.QApplication,
    mode: str,
) -> ThemeSpec:
    normalized = normalize_theme_mode(mode)
    style_hints = app.styleHints()
    target_scheme = (
        QtCore.Qt.ColorScheme.Unknown
        if normalized == THEME_MODE_SYSTEM
        else theme_spec_for_mode(normalized, app).color_scheme
    )
    if hasattr(style_hints, "setColorScheme"):
        style_hints.setColorScheme(target_scheme)
    palette = palette_for_mode(normalized, app)
    if palette is None:
        app.setPalette(app.style().standardPalette())
    else:
        app.setPalette(palette)
    return theme_spec_for_mode(normalized, app)


__all__ = [
    "THEME_MODE_DARK",
    "THEME_MODE_LIGHT",
    "THEME_MODE_SYSTEM",
    "THEME_MODES",
    "THEME_SETTING_KEY",
    "ThemeSpec",
    "apply_theme_mode",
    "normalize_theme_mode",
    "theme_spec_for_mode",
]
