"""
shell_integration - Per-user Windows context-menu ("In Markdown umwandeln").

Registers a verb under
    HKCU\\Software\\Classes\\SystemFileAssociations\\<ext>\\shell\\VoxCastConvert
for every supported extension. No admin rights required (per-user hive).
This module is the single source of truth: the installer calls
``VoxCast.exe --register-shell`` / ``--unregister-shell`` which delegate here,
and the Settings toggle calls register()/unregister() directly.
"""
from __future__ import annotations

import sys
from pathlib import Path

from loguru import logger

VERB = "VoxCastConvert"
LABEL = "In Markdown umwandeln"
_BASE = r"Software\Classes\SystemFileAssociations"


def _supported_exts() -> list[str]:
    # Imported lazily to avoid a hard dependency when only registering.
    from services.conversion_service import SUPPORTED_EXTS
    return sorted(SUPPORTED_EXTS)


def _exe_path() -> str:
    """Resolve the executable used in the context-menu command.

    Frozen build -> the installed VoxCast.exe. Dev mode -> pythonw + main.py
    so the verb still works when testing from source.
    """
    exe = Path(sys.argv[0]).resolve()
    if exe.suffix.lower() == ".exe" and exe.name.lower() != "python.exe" \
            and exe.name.lower() != "pythonw.exe":
        return f'"{exe}"'
    # Dev fallback: launch via python with main.py
    main_py = Path(__file__).resolve().parent.parent / "main.py"
    pyw = Path(sys.executable).with_name("pythonw.exe")
    runner = pyw if pyw.exists() else Path(sys.executable)
    return f'"{runner}" "{main_py}"'


def register(exe_command: str | None = None, icon: str | None = None) -> int:
    """Create the context-menu verb for all supported extensions.

    Returns the number of extensions successfully registered. Idempotent.
    """
    import winreg

    command_exe = exe_command or _exe_path()
    command = f'{command_exe} --convert "%1"'
    if icon is None:
        exe = Path(sys.argv[0]).resolve()
        icon = f"{exe},0" if exe.suffix.lower() == ".exe" else ""

    count = 0
    for ext in _supported_exts():
        try:
            shell_key = rf"{_BASE}\{ext}\shell\{VERB}"
            with winreg.CreateKey(winreg.HKEY_CURRENT_USER, shell_key) as k:
                winreg.SetValueEx(k, None, 0, winreg.REG_SZ, LABEL)
                if icon:
                    winreg.SetValueEx(k, "Icon", 0, winreg.REG_SZ, icon)
            with winreg.CreateKey(
                winreg.HKEY_CURRENT_USER, rf"{shell_key}\command"
            ) as ck:
                winreg.SetValueEx(ck, None, 0, winreg.REG_SZ, command)
            count += 1
        except OSError as e:
            logger.warning("Failed to register context menu for {}: {}", ext, e)
    logger.info("Context menu registered for {} extensions", count)
    return count


def unregister() -> int:
    """Remove the context-menu verb for all supported extensions.

    Returns the number of keys removed. Safe to call when not registered.
    """
    import winreg

    removed = 0
    for ext in _supported_exts():
        shell_key = rf"{_BASE}\{ext}\shell\{VERB}"
        try:
            winreg.DeleteKey(winreg.HKEY_CURRENT_USER, rf"{shell_key}\command")
        except FileNotFoundError:
            pass
        except OSError as e:
            logger.debug("Could not delete command key for {}: {}", ext, e)
        try:
            winreg.DeleteKey(winreg.HKEY_CURRENT_USER, shell_key)
            removed += 1
        except FileNotFoundError:
            pass
        except OSError as e:
            logger.debug("Could not delete shell key for {}: {}", ext, e)
    logger.info("Context menu unregistered ({} keys removed)", removed)
    return removed


def is_registered() -> bool:
    """True if the verb exists for at least one supported extension."""
    import winreg

    for ext in _supported_exts():
        try:
            with winreg.OpenKey(
                winreg.HKEY_CURRENT_USER, rf"{_BASE}\{ext}\shell\{VERB}"
            ):
                return True
        except FileNotFoundError:
            continue
        except OSError:
            continue
    return False
