"""Windows toast + звук для сигналов и анализера."""

from __future__ import annotations

import logging
import sys
from pathlib import Path
from typing import Callable

from aumid_setup import APP_ID
from paths import get_assets_dir

logger = logging.getLogger(__name__)

_window_show: Callable[[], None] | None = None
_mci_lock = __import__("threading").Lock()
_protocol_ready = False


def set_window_show_callback(fn: Callable[[], None] | None) -> None:
    global _window_show
    _window_show = fn


def ensure_notify_protocol() -> None:
    """Регистрирует axon-dump-radar:// для клика по Windows-toast."""
    _ensure_notify_protocol()


def _ensure_notify_protocol() -> None:
    global _protocol_ready
    if _protocol_ready or sys.platform != "win32":
        return
    try:
        import winreg

        proto = "axon-dump-radar"
        if getattr(sys, "frozen", False):
            cmd = f'"{Path(sys.executable).resolve()}" "%1"'
        else:
            entry = (Path(__file__).resolve().parent / "entry.py").resolve()
            cmd = f'"{Path(sys.executable).resolve()}" "{entry}" "%1"'

        key = winreg.CreateKey(winreg.HKEY_CURRENT_USER, rf"Software\Classes\{proto}")
        winreg.SetValueEx(key, "", 0, winreg.REG_SZ, f"URL:{proto}")
        winreg.SetValueEx(key, "URL Protocol", 0, winreg.REG_SZ, "")
        shell = winreg.CreateKey(key, r"shell\open\command")
        winreg.SetValueEx(shell, "", 0, winreg.REG_SZ, cmd)
        winreg.CloseKey(shell)
        winreg.CloseKey(key)
        _protocol_ready = True
    except Exception as e:
        logger.warning("notify protocol registry: %s", e)


def _toast_icon() -> dict | str:
    assets = get_assets_dir()
    for name in ("toast-icon.png", "axon.png"):
        png = assets / name
        if png.exists():
            src = "file:///" + png.resolve().as_posix()
            return {
                "placement": "appLogoOverride",
                "src": src,
            }
    return ""


def _sound_enabled() -> bool:
    try:
        from api_client import ConnectionConfig

        return bool(ConnectionConfig.load().notify_sound_enabled)
    except Exception:
        return True


def _sound_path(kind: str) -> Path | None:
    assets = get_assets_dir()
    name = "notify-analyzer.mp3" if kind == "analyzer" else "notify-signal.mp3"
    path = assets / name
    if path.exists():
        return path
    fallback = assets / "notify-signal.mp3"
    return fallback if fallback.exists() else None


def _play_mp3(path: Path, alias: str) -> None:
    if sys.platform != "win32":
        return
    import ctypes

    winmm = ctypes.windll.winmm
    resolved = str(path.resolve())
    with _mci_lock:
        winmm.mciSendStringW(f"close {alias}", None, 0, None)
        open_cmd = f'open "{resolved}" type mpegvideo alias {alias}'
        if winmm.mciSendStringW(open_cmd, None, 0, None) != 0:
            open_cmd = f'open "{resolved}" alias {alias}'
            if winmm.mciSendStringW(open_cmd, None, 0, None) != 0:
                logger.warning("mci open failed: %s", resolved)
                return
        winmm.mciSendStringW(f"set {alias} volume to 650", None, 0, None)
        winmm.mciSendStringW(f"play {alias}", None, 0, None)


def _play_notify_sound(kind: str) -> None:
    if not _sound_enabled():
        return
    path = _sound_path(kind)
    if not path:
        return
    alias = "axon_analyzer" if kind == "analyzer" else "axon_signal"
    try:
        _play_mp3(path, alias)
    except Exception as e:
        logger.warning("notify sound failed: %s", e)


def _show_windows_toast(title: str, message: str, icon: str, launch: str) -> None:
    from win11toast import notify as win_toast

    kwargs: dict = {
        "title": title,
        "body": message,
        "app_id": APP_ID,
        "audio": {"silent": "true"},
    }
    if icon:
        kwargs["icon"] = icon
    if launch:
        kwargs["on_click"] = launch
    win_toast(**kwargs)
    logger.info("windows toast shown: %s", title)


def play_notify_sound(kind: str = "default") -> bool:
    sound_kind = "analyzer" if kind == "analyzer" else "signal"
    try:
        _play_notify_sound(sound_kind)
        return True
    except Exception as e:
        logger.warning("play_notify_sound: %s", e)
        return False


def notify(
    title: str,
    message: str,
    kind: str = "default",
    action: str = "",
    app_foreground: bool = False,
    force_toast: bool = False,
) -> bool:
    title = str(title or "").strip() or "AXON Dump Radar"
    message = str(message or "").strip()
    if not message:
        message = title

    from panel_state import is_panel_hidden, should_show_windows_toast

    hidden = is_panel_hidden()
    if hidden:
        app_foreground = False

    always_toast = force_toast or kind in ("signal", "tp")
    show_windows = should_show_windows_toast(bool(app_foreground), force=always_toast)
    icon = _toast_icon()
    sound_kind = "analyzer" if kind == "analyzer" else "signal"
    launch = ""
    act = str(action or "").strip()
    if act and show_windows:
        _ensure_notify_protocol()
        launch = f"axon-dump-radar:{act}"

    _play_notify_sound(sound_kind)

    if not show_windows:
        return True

    try:
        _show_windows_toast(title, message, icon, launch)
    except Exception as e:
        logger.warning("windows toast failed: %s", e)
        try:
            from win11toast import toast as simple_toast

            simple_toast(title, message, app_id=APP_ID)
            logger.info("windows toast fallback ok: %s", title)
        except Exception as e2:
            logger.warning("windows toast fallback failed: %s", e2)
            return False

    return True
