"""System tray icon for Media Server."""

import ctypes
import io
import logging
import sys
import webbrowser
from pathlib import Path
from typing import Callable

from PIL import Image, ImageDraw

logger = logging.getLogger(__name__)

# pystray is optional — tray silently disabled when missing
try:
    import pystray

    PYSTRAY_AVAILABLE = True
except ImportError:
    pystray = None
    PYSTRAY_AVAILABLE = False


# Windows-native confirmation (no tkinter needed)
_MB_YESNO = 0x04
_MB_ICONQUESTION = 0x20
_MB_TOPMOST = 0x40000
_MB_SETFOREGROUND = 0x10000
_IDYES = 6


def _confirm(title: str, message: str) -> bool:
    """Show a Yes/No dialog before a destructive tray action.

    Uses the native Windows MessageBox on win32; on Linux/macOS we don't
    have a no-dependency GUI dialog available (Tk pulls in tkinter, gtk
    pulls in PyGObject), so we log + auto-confirm — the tray menu items
    themselves require a deliberate click already.
    """
    if sys.platform == "win32":
        result = ctypes.windll.user32.MessageBoxW(
            0,
            message,
            title,
            _MB_YESNO | _MB_ICONQUESTION | _MB_TOPMOST | _MB_SETFOREGROUND,
        )
        return result == _IDYES

    logger.info("Tray confirm (auto-yes on non-Windows): %s — %s", title, message)
    return True


def _create_icon_image(size: int = 64) -> Image.Image:
    """Create a tray icon: green circle with white play triangle."""
    img = Image.new("RGBA", (size, size), (0, 0, 0, 0))
    draw = ImageDraw.Draw(img)

    # Green circle background
    padding = 2
    draw.ellipse(
        [padding, padding, size - padding, size - padding],
        fill=(29, 185, 84, 255),
    )

    # White play triangle
    cx, cy = size // 2, size // 2
    r = size * 0.28
    triangle = [
        (cx - r * 0.6, cy - r),
        (cx - r * 0.6, cy + r),
        (cx + r * 0.9, cy),
    ]
    draw.polygon(triangle, fill=(255, 255, 255, 255))

    return img


def _load_icon_image() -> Image.Image:
    """Load the ICO/SVG app icon, falling back to a generated image."""
    icons_dir = Path(__file__).parent / "static" / "icons"

    # Try .ico first (best for Windows tray)
    ico_path = icons_dir / "icon.ico"
    if ico_path.exists():
        try:
            return Image.open(ico_path)
        except Exception:
            pass

    # Try SVG via cairosvg
    try:
        import cairosvg

        svg_path = icons_dir / "icon.svg"
        if svg_path.exists():
            png_data = cairosvg.svg2png(url=str(svg_path), output_width=64, output_height=64)
            return Image.open(io.BytesIO(png_data))
    except Exception:
        pass

    return _create_icon_image()


class TrayManager:
    """Manages the system tray icon and its context menu.

    Call ``run()`` on the **main thread** — it blocks until ``stop()``
    is called (from any thread) or the user picks *Shutdown* from the menu.
    """

    def __init__(self, port: int, on_exit: Callable[[], None]) -> None:
        if not PYSTRAY_AVAILABLE:
            raise ImportError("pystray is required for system tray support")

        self._port = port
        self._on_exit = on_exit
        # Initialize so the property and any cross-thread reader cannot ever
        # observe an uninitialized attribute. Set before _on_exit() fires.
        self._restart_requested = False

        menu = pystray.Menu(
            pystray.MenuItem("Show UI", self._show_ui, default=True),
            pystray.Menu.SEPARATOR,
            pystray.MenuItem("Restart", self._restart),
            pystray.MenuItem("Shutdown", self._shutdown),
        )

        self._icon = pystray.Icon(
            name="media-server",
            icon=_load_icon_image(),
            title="Media Server",
            menu=menu,
        )

    def _show_ui(self, icon: "pystray.Icon", item: "pystray.MenuItem") -> None:
        webbrowser.open(f"http://localhost:{self._port}")

    def _restart(self, icon: "pystray.Icon", item: "pystray.MenuItem") -> None:
        if not _confirm("Media Server", "Restart the server?"):
            return
        logger.info("Restart requested from tray")
        # Set the flag BEFORE signalling exit so the main thread observes it
        # when it wakes from server_thread.join() — order matters across the
        # tray/uvicorn handoff.
        self._restart_requested = True
        self._on_exit()
        self._icon.stop()

    @property
    def restart_requested(self) -> bool:
        return self._restart_requested

    def _shutdown(self, icon: "pystray.Icon", item: "pystray.MenuItem") -> None:
        if not _confirm("Media Server", "Shut down the server?"):
            return
        logger.info("Shutdown requested from tray")
        self._on_exit()
        self._icon.stop()

    def run(self) -> None:
        """Block the calling thread running the tray message loop."""
        self._icon.run()

    def stop(self) -> None:
        """Stop the tray icon from any thread."""
        self._icon.stop()
