"""
Configuration constants, CLI flags, and glyph tables.
Supports both global constants (backward compatible) and injected config for testing.
"""

import sys
from dataclasses import dataclass, field
from pathlib import Path

_REPO_ROOT = Path(__file__).resolve().parent.parent
_FONT_EXTENSIONS = {".otf", ".ttf", ".ttc"}


def _arg_value(flag, argv: list[str] | None = None):
    """Get value following a CLI flag, if present."""
    argv = argv or sys.argv
    if flag not in argv:
        return None
    i = argv.index(flag)
    return argv[i + 1] if i + 1 < len(argv) else None


def _arg_int(flag, default, argv: list[str] | None = None):
    """Get int CLI argument with safe fallback."""
    raw = _arg_value(flag, argv)
    if raw is None:
        return default
    try:
        return int(raw)
    except ValueError:
        return default


def _resolve_font_path(raw_path):
    """Resolve font path; relative paths are anchored to repo root."""
    p = Path(raw_path).expanduser()
    if p.is_absolute():
        return str(p)
    return str((_REPO_ROOT / p).resolve())


def _list_font_files(font_dir):
    """List supported font files within a font directory."""
    font_root = Path(font_dir)
    if not font_root.exists() or not font_root.is_dir():
        return []
    return [
        str(path.resolve())
        for path in sorted(font_root.iterdir())
        if path.is_file() and path.suffix.lower() in _FONT_EXTENSIONS
    ]


def list_repo_font_files():
    """Public helper for discovering repository font files."""
    return _list_font_files(FONT_DIR)


def _get_platform_font_paths() -> dict[str, str]:
    """Get platform-appropriate font paths for non-Latin scripts."""
    import platform

    system = platform.system()

    if system == "Darwin":
        return {
            "zh-cn": "/System/Library/Fonts/STHeiti Medium.ttc",
            "ja": "/System/Library/Fonts/ヒラギノ角ゴシック W9.ttc",
            "ko": "/System/Library/Fonts/AppleSDGothicNeo.ttc",
            "ru": "/System/Library/Fonts/Supplemental/Arial.ttf",
            "uk": "/System/Library/Fonts/Supplemental/Arial.ttf",
            "el": "/System/Library/Fonts/Supplemental/Arial.ttf",
            "he": "/System/Library/Fonts/Supplemental/Arial.ttf",
            "ar": "/System/Library/Fonts/GeezaPro.ttc",
            "fa": "/System/Library/Fonts/GeezaPro.ttc",
            "hi": "/System/Library/Fonts/Kohinoor.ttc",
            "th": "/System/Library/Fonts/ThonburiUI.ttc",
        }
    elif system == "Linux":
        return {
            "zh-cn": "/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc",
            "ja": "/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc",
            "ko": "/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc",
            "ru": "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
            "uk": "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
            "el": "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
            "he": "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
            "ar": "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
            "fa": "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
            "hi": "/usr/share/fonts/truetype/noto/NotoSansDevanagari-Regular.ttf",
            "th": "/usr/share/fonts/truetype/noto/NotoSansThai-Regular.ttf",
        }
    else:
        return {}


@dataclass(frozen=True)
class Config:
    """Immutable configuration container for injected config."""

    headline_limit: int = 1000
    feed_timeout: int = 10
    mic_threshold_db: int = 50
    mode: str = "news"
    firehose: bool = False

    ntfy_topic: str = "https://ntfy.sh/klubhaus_terminal_mainline/json"
    ntfy_cc_cmd_topic: str = "https://ntfy.sh/klubhaus_terminal_mainline_cc_cmd/json"
    ntfy_cc_resp_topic: str = "https://ntfy.sh/klubhaus_terminal_mainline_cc_resp/json"
    ntfy_reconnect_delay: int = 5
    message_display_secs: int = 30

    font_dir: str = "fonts"
    font_path: str = ""
    font_index: int = 0
    font_picker: bool = True
    font_sz: int = 60
    render_h: int = 8

    ssaa: int = 4

    scroll_dur: float = 5.625
    frame_dt: float = 0.05
    firehose_h: int = 12
    grad_speed: float = 0.08

    glitch_glyphs: str = "░▒▓█▌▐╌╍╎╏┃┆┇┊┋"
    kata_glyphs: str = "ﾊﾐﾋｰｳｼﾅﾓﾆｻﾜﾂｵﾘｱﾎﾃﾏｹﾒｴｶｷﾑﾕﾗｾﾈｽﾀﾇﾍ"

    script_fonts: dict[str, str] = field(default_factory=_get_platform_font_paths)

    display: str = "pygame"
    positioning: str = "mixed"
    websocket: bool = False
    websocket_port: int = 8765
    theme: str = "green"

    @classmethod
    def from_args(cls, argv: list[str] | None = None) -> "Config":
        """Create Config from CLI arguments (or custom argv for testing)."""
        argv = argv or sys.argv

        font_dir = _resolve_font_path(_arg_value("--font-dir", argv) or "fonts")
        font_file_arg = _arg_value("--font-file", argv)
        font_files = _list_font_files(font_dir)
        font_path = (
            _resolve_font_path(font_file_arg)
            if font_file_arg
            else (font_files[0] if font_files else "")
        )

        return cls(
            headline_limit=1000,
            feed_timeout=10,
            mic_threshold_db=50,
            mode="poetry" if "--poetry" in argv or "-p" in argv else "news",
            firehose="--firehose" in argv,
            ntfy_topic="https://ntfy.sh/klubhaus_terminal_mainline/json",
            ntfy_cc_cmd_topic="https://ntfy.sh/klubhaus_terminal_mainline_cc_cmd/json",
            ntfy_cc_resp_topic="https://ntfy.sh/klubhaus_terminal_mainline_cc_resp/json",
            ntfy_reconnect_delay=5,
            message_display_secs=30,
            font_dir=font_dir,
            font_path=font_path,
            font_index=max(0, _arg_int("--font-index", 0, argv)),
            font_picker="--no-font-picker" not in argv,
            font_sz=60,
            render_h=8,
            ssaa=4,
            scroll_dur=5.625,
            frame_dt=0.05,
            firehose_h=12,
            grad_speed=0.08,
            glitch_glyphs="░▒▓█▌▐╌╍╎╏┃┆┇┊┋",
            kata_glyphs="ﾊﾐﾋｰｳｼﾅﾓﾆｻﾜﾂｵﾘｱﾎﾃﾏｹﾒｴｶｷﾑﾕﾗｾﾈｽﾀﾇﾍ",
            script_fonts=_get_platform_font_paths(),
            display=_arg_value("--display", argv) or "terminal",
            positioning=_arg_value("--positioning", argv) or "mixed",
            websocket="--websocket" in argv,
            websocket_port=_arg_int("--websocket-port", 8765, argv),
            theme=_arg_value("--theme", argv) or "green",
        )


_config: Config | None = None


def get_config() -> Config:
    """Get the global config instance (lazy-loaded)."""
    global _config
    if _config is None:
        _config = Config.from_args()
    return _config


def set_config(config: Config) -> None:
    """Set the global config instance (for testing)."""
    global _config
    _config = config


# ─── RUNTIME ──────────────────────────────────────────────
HEADLINE_LIMIT = 1000
FEED_TIMEOUT = 10
MIC_THRESHOLD_DB = 50  # dB above which glitches intensify
MODE = "poetry" if "--poetry" in sys.argv or "-p" in sys.argv else "news"
FIREHOSE = "--firehose" in sys.argv

# ─── NTFY MESSAGE QUEUE ──────────────────────────────────
NTFY_TOPIC = "https://ntfy.sh/klubhaus_terminal_mainline/json"
NTFY_CC_CMD_TOPIC = "https://ntfy.sh/klubhaus_terminal_mainline_cc_cmd/json"
NTFY_CC_RESP_TOPIC = "https://ntfy.sh/klubhaus_terminal_mainline_cc_resp/json"
NTFY_RECONNECT_DELAY = 5  # seconds before reconnecting after a dropped stream
MESSAGE_DISPLAY_SECS = 30  # how long a message holds the screen

# ─── FONT RENDERING ──────────────────────────────────────
FONT_DIR = _resolve_font_path(_arg_value("--font-dir") or "fonts")
_FONT_FILE_ARG = _arg_value("--font-file")
_FONT_FILES = _list_font_files(FONT_DIR)
FONT_PATH = (
    _resolve_font_path(_FONT_FILE_ARG)
    if _FONT_FILE_ARG
    else (_FONT_FILES[0] if _FONT_FILES else "")
)
FONT_INDEX = max(0, _arg_int("--font-index", 0))
FONT_PICKER = "--no-font-picker" not in sys.argv
FONT_SZ = 60
RENDER_H = 8  # terminal rows per rendered text line

# ─── FONT RENDERING (ADVANCED) ────────────────────────────
SSAA = 4  # super-sampling factor: render at SSAA× then downsample

# ─── SCROLL / FRAME ──────────────────────────────────────
SCROLL_DUR = 5.625  # seconds per headline (2/3 original speed)
FRAME_DT = 0.05  # 50ms base frame rate (20 FPS)
FIREHOSE_H = 12  # firehose zone height (terminal rows)
GRAD_SPEED = 0.08  # gradient traversal speed (cycles/sec, ~12s full sweep)

# ─── GLYPHS ───────────────────────────────────────────────
GLITCH = "░▒▓█▌▐╌╍╎╏┃┆┇┊┋"
KATA = "ﾊﾐﾋｰｳｼﾅﾓﾆｻﾜﾂｵﾘｱﾎﾃﾏｹﾒｴｶｷﾑﾕﾗｾﾈｽﾀﾇﾍ"

# ─── WEBSOCKET ─────────────────────────────────────────────
DISPLAY = _arg_value("--display", sys.argv) or "pygame"
WEBSOCKET = "--websocket" in sys.argv
WEBSOCKET_PORT = _arg_int("--websocket-port", 8765)

# ─── DEMO MODE ────────────────────────────────────────────
DEMO = "--demo" in sys.argv
DEMO_EFFECT_DURATION = 5.0  # seconds per effect
PIPELINE_DEMO = "--pipeline-demo" in sys.argv

# ─── THEME MANAGEMENT ─────────────────────────────────────────
ACTIVE_THEME = None


def set_active_theme(theme_id: str = "green"):
    """Set the active theme by ID.

    Args:
        theme_id: Theme identifier from theme registry (e.g., "green", "orange", "purple")

    Raises:
        KeyError: If theme_id is not in the theme registry

    Side Effects:
        Sets the ACTIVE_THEME global variable
    """
    global ACTIVE_THEME
    from engine import themes

    ACTIVE_THEME = themes.get_theme(theme_id)


# Initialize theme on module load (lazy to avoid circular dependency)
def _init_theme():
    theme_id = _arg_value("--theme", sys.argv) or "green"
    try:
        set_active_theme(theme_id)
    except KeyError:
        pass  # Theme not found, keep None


_init_theme()


# ─── PIPELINE MODE (new unified architecture) ─────────────
PIPELINE_MODE = "--pipeline" in sys.argv
PIPELINE_PRESET = _arg_value("--pipeline-preset", sys.argv) or "demo"

# ─── PRESET MODE ────────────────────────────────────────────
PRESET = _arg_value("--preset", sys.argv)

# ─── PIPELINE DIAGRAM ────────────────────────────────────
PIPELINE_DIAGRAM = "--pipeline-diagram" in sys.argv

# ─── THEME ──────────────────────────────────────────────────
THEME = _arg_value("--theme", sys.argv) or "green"


def set_font_selection(font_path=None, font_index=None):
    """Set runtime primary font selection."""
    global FONT_PATH, FONT_INDEX
    if font_path is not None:
        FONT_PATH = _resolve_font_path(font_path)
    if font_index is not None:
        FONT_INDEX = max(0, int(font_index))
