"""
reauth_notifier.py — Token-expiry detection and multi-channel notification.

Tracks consecutive 401 responses across all API calls.  After
CONSECUTIVE_401_THRESHOLD failures it:

  1. Writes a marker file that Electron reads on next startup.
  2. Fires an OS desktop notification (works even when Electron is not running).
  3. Sends a 'token_expired' IPC message if the Electron IPC channel is live.

Calling on_auth_success() resets the counter and clears the marker file.

Thread-safe: all state updates use a threading.Lock.
"""

import os
import platform
import subprocess
import threading
from pathlib import Path

from ws_package.log.writer import LogWriter

logger = LogWriter.file(__name__)

# Trigger after this many back-to-back 401s across different API calls.
CONSECUTIVE_401_THRESHOLD = 3

# ── Marker-file path (same base dir as Electron SQLite DB) ──────────────────

def _marker_path() -> Path:
    home = Path.home()
    system = platform.system()
    if system == "Darwin":
        base = home / "Library" / "Application Support" / "Workstatus"
    elif system == "Linux":
        base = home / "Workstatus"
    else:  # Windows
        appdata = os.environ.get("APPDATA") or str(home / "AppData" / "Roaming")
        base = Path(appdata) / "Workstatus"
    base.mkdir(parents=True, exist_ok=True)
    return base / ".reauth_needed"


# ── OS desktop notification (no Electron dependency) ────────────────────────

_NOTIF_TITLE = "WorkStatus — Re-login required"
_NOTIF_BODY  = "Your session has expired. Open WorkStatus to re-login and resume tracking."

def _send_os_notification() -> None:
    """Fire a native desktop notification via platform tools — no extra deps."""
    system = platform.system()
    try:
        if system == "Darwin":
            script = (
                f'display notification "{_NOTIF_BODY}" '
                f'with title "{_NOTIF_TITLE}" '
                f'sound name "Basso"'
            )
            subprocess.Popen(["osascript", "-e", script],
                             stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

        elif system == "Linux":
            subprocess.Popen(
                ["notify-send", "--urgency=critical", "--expire-time=0",
                 _NOTIF_TITLE, _NOTIF_BODY],
                stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
            )

        else:  # Windows — use PowerShell toast (no extra packages)
            ps_script = (
                "Add-Type -AssemblyName System.Windows.Forms; "
                "$n = New-Object System.Windows.Forms.NotifyIcon; "
                "$n.Icon = [System.Drawing.SystemIcons]::Information; "
                "$n.Visible = $true; "
                f'$n.ShowBalloonTip(10000, "{_NOTIF_TITLE}", "{_NOTIF_BODY}", '
                "[System.Windows.Forms.ToolTipIcon]::Warning); "
                "Start-Sleep -Seconds 12; "
                "$n.Dispose()"
            )
            subprocess.Popen(
                ["powershell.exe", "-NoProfile", "-WindowStyle", "Hidden",
                 "-Command", ps_script],
                stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
            )
    except Exception as exc:
        logger.warning("reauth_notifier: OS notification failed (non-fatal): %s", exc)


# ── Main class ───────────────────────────────────────────────────────────────

class ReauthNotifier:
    """Singleton-safe 401 tracker and notification dispatcher."""

    def __init__(self) -> None:
        self._lock              = threading.Lock()
        self._consecutive_401s  = 0
        self._notified          = False   # Avoid repeated OS notifications

    # ── Public API ───────────────────────────────────────────────────────────

    def on_401(self) -> None:
        """Call every time an API response returns HTTP 401."""
        with self._lock:
            self._consecutive_401s += 1
            count = self._consecutive_401s
            already = self._notified

        logger.warning(
            "reauth_notifier: 401 detected (consecutive=%d, threshold=%d)",
            count, CONSECUTIVE_401_THRESHOLD
        )

        if count >= CONSECUTIVE_401_THRESHOLD and not already:
            self._trigger_reauth()

    def on_auth_success(self) -> None:
        """Call after a successful authentication to reset all state."""
        with self._lock:
            was_notified    = self._notified
            self._consecutive_401s = 0
            self._notified  = False

        if was_notified:
            self._clear_marker()
            logger.info("reauth_notifier: auth succeeded — marker cleared, counter reset")
        else:
            logger.debug("reauth_notifier: auth succeeded, counter reset")

    def is_reauth_needed(self) -> bool:
        """Return True if the marker file is present."""
        return _marker_path().exists()

    # ── Internal helpers ─────────────────────────────────────────────────────

    def _trigger_reauth(self) -> None:
        """Write marker, send OS notification, send IPC message."""
        with self._lock:
            self._notified = True

        logger.error(
            "reauth_notifier: token appears expired after %d consecutive 401s — notifying",
            CONSECUTIVE_401_THRESHOLD
        )

        # 1. Marker file — Electron reads this on next startup
        self._write_marker()

        # 2. OS notification — works even with no Electron running
        _send_os_notification()

        # 3. IPC message — if Electron is connected right now
        self._send_ipc_token_expired()

    def _write_marker(self) -> None:
        try:
            _marker_path().write_text("reauth_needed", encoding="utf-8")
            logger.info("reauth_notifier: marker written to %s", _marker_path())
        except Exception as exc:
            logger.warning("reauth_notifier: could not write marker file: %s", exc)

    def _clear_marker(self) -> None:
        try:
            path = _marker_path()
            if path.exists():
                path.unlink()
                logger.info("reauth_notifier: marker cleared")
        except Exception as exc:
            logger.warning("reauth_notifier: could not clear marker file: %s", exc)

    def _send_ipc_token_expired(self) -> None:
        try:
            from ws_package.utils.electron_comm import get_electron_comm
            ec = get_electron_comm()
            if ec and ec.is_connected():
                ec.send_to_electron("token_expired", {
                    "reason": "consecutive_401",
                    "consecutive_count": self._consecutive_401s,
                })
                logger.info("reauth_notifier: sent token_expired IPC to Electron")
            else:
                logger.info("reauth_notifier: Electron not connected — IPC skipped (marker + OS notif sent)")
        except Exception as exc:
            logger.warning("reauth_notifier: IPC send failed (non-fatal): %s", exc)


# ── Module-level singleton ───────────────────────────────────────────────────

_notifier: ReauthNotifier = ReauthNotifier()


def get_reauth_notifier() -> ReauthNotifier:
    return _notifier
