"""Wine theme management for Proton prefixes.

Safely applies dark/light color schemes to Wine prefixes via registry.
Only modifies string and dword values — never touches binary/hex data.
"""

from __future__ import annotations

import re
from pathlib import Path
from typing import Iterator

# Registry section pattern
_SECTION_RE = re.compile(r'^\[([^\]]+)\]', re.MULTILINE)

# Wine dark color scheme (Control Panel\Colors)
# Format: "R G B" strings
DARK_COLORS = {
    "ActiveBorder": "49 54 59",
    "ActiveTitle": "49 54 59",
    "AppWorkSpace": "30 30 30",
    "Background": "30 30 30",
    "ButtonAlternateFace": "49 54 59",
    "ButtonDkShadow": "20 20 20",
    "ButtonFace": "49 54 59",
    "ButtonHilight": "70 75 80",
    "ButtonLight": "60 65 70",
    "ButtonShadow": "35 38 41",
    "ButtonText": "230 230 230",
    "GradientActiveTitle": "49 54 59",
    "GradientInactiveTitle": "40 42 45",
    "GrayText": "128 128 128",
    "Hilight": "61 174 233",
    "HilightText": "255 255 255",
    "HotTrackingColor": "61 174 233",
    "InactiveBorder": "40 42 45",
    "InactiveTitle": "40 42 45",
    "InactiveTitleText": "128 128 128",
    "InfoText": "230 230 230",
    "InfoWindow": "49 54 59",
    "Menu": "49 54 59",
    "MenuBar": "49 54 59",
    "MenuHilight": "61 174 233",
    "MenuText": "230 230 230",
    "Scrollbar": "49 54 59",
    "TitleText": "230 230 230",
    "Window": "35 38 41",
    "WindowFrame": "49 54 59",
    "WindowText": "230 230 230",
}

# Standard light colors (Windows defaults)
LIGHT_COLORS = {
    "ActiveBorder": "180 180 180",
    "ActiveTitle": "153 180 209",
    "AppWorkSpace": "171 171 171",
    "Background": "0 0 0",
    "ButtonAlternateFace": "0 0 0",
    "ButtonDkShadow": "105 105 105",
    "ButtonFace": "240 240 240",
    "ButtonHilight": "255 255 255",
    "ButtonLight": "227 227 227",
    "ButtonShadow": "160 160 160",
    "ButtonText": "0 0 0",
    "GradientActiveTitle": "185 209 234",
    "GradientInactiveTitle": "215 228 242",
    "GrayText": "109 109 109",
    "Hilight": "0 120 215",
    "HilightText": "255 255 255",
    "HotTrackingColor": "0 102 204",
    "InactiveBorder": "244 247 252",
    "InactiveTitle": "191 205 219",
    "InactiveTitleText": "0 0 0",
    "InfoText": "0 0 0",
    "InfoWindow": "255 255 225",
    "Menu": "240 240 240",
    "MenuBar": "240 240 240",
    "MenuHilight": "0 120 215",
    "MenuText": "0 0 0",
    "Scrollbar": "200 200 200",
    "TitleText": "0 0 0",
    "Window": "255 255 255",
    "WindowFrame": "100 100 100",
    "WindowText": "0 0 0",
}

# Color scheme presets
COLOR_SCHEMES = {
    "dark": DARK_COLORS,
    "light": LIGHT_COLORS,
}

# DWM (Desktop Window Manager) settings for dark theme
# AccentColor is ABGR format as dword
DARK_DWM = {
    "AccentColor": 0xff3b3b3b,           # Dark gray accent
    "AccentColorInactive": 0xff2d2d2d,   # Darker inactive
    "ColorizationAfterglow": 0xc43b3b3b,
    "ColorizationColor": 0xc43b3b3b,
    "ColorizationColorBalance": 0x59,
    "ColorizationGlassAttribute": 0x01,
    "ColorPrevalence": 0x01,             # Use accent color on title bars
    "EnableWindowColorization": 0x01,
}

LIGHT_DWM = {
    "AccentColor": 0xffd77800,           # Blue accent (Windows default)
    "AccentColorInactive": 0xffdbdbdb,
    "ColorizationAfterglow": 0xc44f8bcd,
    "ColorizationColor": 0xc44f8bcd,
    "ColorizationColorBalance": 0x59,
    "ColorizationGlassAttribute": 0x01,
    "ColorPrevalence": 0x00,
    "EnableWindowColorization": 0x01,
}

DWM_SCHEMES = {
    "dark": DARK_DWM,
    "light": LIGHT_DWM,
}

# Explorer accent settings
DARK_EXPLORER = {
    "AccentColorMenu": 0xff3b3b3b,
}

LIGHT_EXPLORER = {
    "AccentColorMenu": 0xffd77800,
}

EXPLORER_SCHEMES = {
    "dark": DARK_EXPLORER,
    "light": LIGHT_EXPLORER,
}

# Vual's own Wine prefix
VUAL_PREFIX = Path.home() / ".local" / "share" / "vual" / "wine_prefix"


def get_vual_prefix() -> Path | None:
    """Return Vual's Wine prefix if it exists."""
    if VUAL_PREFIX.is_dir() and (VUAL_PREFIX / "user.reg").is_file():
        return VUAL_PREFIX
    return None


def get_all_prefixes(steamapps: Path) -> Iterator[Path]:
    """Yield all Proton prefix paths under steamapps/compatdata."""
    compatdata = steamapps / "compatdata"
    if not compatdata.is_dir():
        return
    
    for entry in compatdata.iterdir():
        if not entry.is_dir():
            continue
        # Skip non-numeric (not app IDs)
        if not entry.name.isdigit():
            continue
        
        pfx = entry / "pfx"
        if pfx.is_dir():
            yield pfx


def _find_or_create_section(lines: list[str], section_name: str) -> int:
    """Find section index or create it. Returns index of first line after section header.
    
    Wine registry sections can have timestamps: [Section\\Name] 1234567890
    We match by prefix to handle this.
    """
    target = f"[{section_name}]"
    target_lower = target.lower()
    
    for i, line in enumerate(lines):
        stripped = line.strip().lower()
        # Match exact or with timestamp suffix
        if stripped == target_lower or stripped.startswith(target_lower + " "):
            return i + 1
    
    # Section not found — add at end
    if lines and lines[-1].strip():
        lines.append("")
    lines.append(target)
    lines.append("")
    return len(lines) - 1


def _set_string_value(lines: list[str], section_idx: int, key: str, value: str) -> None:
    """Set a string value in registry section. Only modifies string values."""
    # Find section end (next section or EOF)
    section_end = len(lines)
    for i in range(section_idx, len(lines)):
        if lines[i].startswith("["):
            section_end = i
            break
    
    # Look for existing key
    key_pattern = f'"{key}"='
    for i in range(section_idx, section_end):
        if lines[i].startswith(key_pattern):
            lines[i] = f'"{key}"="{value}"'
            return
    
    # Key not found — insert before section end
    insert_at = section_end
    # Find last non-empty line in section
    for i in range(section_end - 1, section_idx - 1, -1):
        if lines[i].strip():
            insert_at = i + 1
            break
    
    lines.insert(insert_at, f'"{key}"="{value}"')


def _set_dword_value(lines: list[str], section_idx: int, key: str, value: int) -> None:
    """Set a dword value in registry section."""
    # Find section end (next section or EOF)
    section_end = len(lines)
    for i in range(section_idx, len(lines)):
        if lines[i].startswith("["):
            section_end = i
            break
    
    # Format: "Key"=dword:00000000
    dword_str = f'"{key}"=dword:{value:08x}'
    
    # Look for existing key
    key_pattern = f'"{key}"='
    for i in range(section_idx, section_end):
        if lines[i].startswith(key_pattern):
            lines[i] = dword_str
            return
    
    # Key not found — insert before section end
    insert_at = section_end
    for i in range(section_end - 1, section_idx - 1, -1):
        if lines[i].strip():
            insert_at = i + 1
            break
    
    lines.insert(insert_at, dword_str)


def apply_colors_to_prefix(pfx: Path, colors: dict[str, str], is_dark: bool) -> bool:
    """Apply color scheme to a single prefix.
    
    Modifies:
    - [Control Panel\\Colors] — color values as "R G B" strings
    - [Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize] — dark mode flags
    
    Args:
        pfx: Path to prefix directory (containing user.reg).
        colors: Dict of color name -> "R G B" string values.
        is_dark: True for dark theme, False for light.
    
    Returns:
        True if successful, False otherwise.
    """
    user_reg = pfx / "user.reg"
    if not user_reg.is_file():
        return False
    
    try:
        content = user_reg.read_text(encoding="utf-8", errors="replace")
    except OSError:
        return False
    
    lines = content.splitlines()
    
    # Find or create Colors section
    colors_idx = _find_or_create_section(
        lines, 
        "Control Panel\\\\Colors"  # Escaped backslash for .reg format
    )
    
    # Apply each color
    for key, value in colors.items():
        _set_string_value(lines, colors_idx, key, value)
    
    # Find or create Personalize section (Windows 10+ dark mode)
    personalize_idx = _find_or_create_section(
        lines,
        "Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Themes\\\\Personalize"
    )
    
    # Set dark mode flags: 0 = dark, 1 = light
    light_value = 0 if is_dark else 1
    _set_dword_value(lines, personalize_idx, "AppsUseLightTheme", light_value)
    _set_dword_value(lines, personalize_idx, "SystemUsesLightTheme", light_value)
    
    # Find or create DWM section for titlebar colors
    dwm_idx = _find_or_create_section(
        lines,
        "Software\\\\Microsoft\\\\Windows\\\\DWM"
    )
    
    # Apply DWM settings
    dwm_settings = DARK_DWM if is_dark else LIGHT_DWM
    for key, value in dwm_settings.items():
        _set_dword_value(lines, dwm_idx, key, value)
    
    # Find or create Explorer Accent section
    explorer_idx = _find_or_create_section(
        lines,
        "Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Explorer\\\\Accent"
    )
    
    # Apply Explorer accent settings
    explorer_settings = DARK_EXPLORER if is_dark else LIGHT_EXPLORER
    for key, value in explorer_settings.items():
        _set_dword_value(lines, explorer_idx, key, value)
    
    # Find ThemeManager section and disable msstyles for dark theme
    # (Wine visual styles can override our color settings)
    theme_mgr_idx = _find_or_create_section(
        lines,
        "Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\ThemeManager"
    )
    
    if is_dark:
        # Disable visual styles to use our dark colors
        _set_string_value(lines, theme_mgr_idx, "ThemeActive", "0")
    else:
        _set_string_value(lines, theme_mgr_idx, "ThemeActive", "1")
    
    # Write back
    try:
        user_reg.write_text("\n".join(lines) + "\n", encoding="utf-8")
        return True
    except OSError:
        return False


def apply_theme_to_all(steamapps: Path, theme: str) -> tuple[int, int]:
    """Apply theme to all Proton prefixes and Vual's own prefix.
    
    Args:
        steamapps: Path to Steam/steamapps directory.
        theme: Theme name ("dark", "light", or "system").
    
    Returns:
        Tuple of (success_count, fail_count).
    """
    if theme == "system" or theme not in COLOR_SCHEMES:
        return (0, 0)
    
    colors = COLOR_SCHEMES[theme]
    is_dark = (theme == "dark")
    success = 0
    failed = 0
    
    # Apply to Steam prefixes
    for pfx in get_all_prefixes(steamapps):
        if apply_colors_to_prefix(pfx, colors, is_dark):
            success += 1
        else:
            failed += 1
    
    # Apply to Vual's own prefix
    vual_pfx = get_vual_prefix()
    if vual_pfx:
        if apply_colors_to_prefix(vual_pfx, colors, is_dark):
            success += 1
        else:
            failed += 1
    
    return (success, failed)


