"""
Dead man's switch.

Check in periodically. If you don't, the system executes the killswitch
after a grace period. State persisted to ~/.soosef/fieldkit/deadman.json.
"""

from __future__ import annotations

import json
import logging
from datetime import UTC, datetime, timedelta
from pathlib import Path

import soosef.paths as _paths

logger = logging.getLogger(__name__)


class DeadmanSwitch:
    """Timer-based auto-purge if operator fails to check in."""

    def __init__(self, state_file: Path | None = None):
        self._state_file = state_file or _paths.DEADMAN_STATE

    def _load_state(self) -> dict:
        if self._state_file.exists():
            with open(self._state_file) as f:
                return json.load(f)  # type: ignore[no-any-return]
        return {
            "armed": False,
            "last_checkin": None,
            "interval_hours": 24,
            "grace_hours": 2,
        }

    def _save_state(self, state: dict) -> None:
        self._state_file.parent.mkdir(parents=True, exist_ok=True)
        with open(self._state_file, "w") as f:
            json.dump(state, f, indent=2)

    def arm(self, interval_hours: int = 24, grace_hours: int = 2) -> None:
        """Arm the dead man's switch and record initial check-in."""
        state = self._load_state()
        state["armed"] = True
        state["interval_hours"] = interval_hours
        state["grace_hours"] = grace_hours
        state["last_checkin"] = datetime.now(UTC).isoformat()
        self._save_state(state)
        logger.info("Dead man's switch armed: %dh interval, %dh grace", interval_hours, grace_hours)

    def disarm(self) -> None:
        """Disarm the dead man's switch."""
        state = self._load_state()
        state["armed"] = False
        self._save_state(state)
        logger.info("Dead man's switch disarmed")

    def checkin(self) -> None:
        """Record a check-in, resetting the timer."""
        state = self._load_state()
        state["last_checkin"] = datetime.now(UTC).isoformat()
        self._save_state(state)
        logger.info("Dead man's switch check-in recorded")

    def is_armed(self) -> bool:
        return self._load_state()["armed"]  # type: ignore[no-any-return]

    def is_overdue(self) -> bool:
        """Check if the switch has expired (past interval, ignoring grace)."""
        state = self._load_state()
        if not state["armed"] or not state["last_checkin"]:
            return False
        last = datetime.fromisoformat(state["last_checkin"])
        deadline = last + timedelta(hours=state["interval_hours"])
        return datetime.now(UTC) > deadline

    def should_fire(self) -> bool:
        """Check if the switch should fire (past interval + grace)."""
        state = self._load_state()
        if not state["armed"] or not state["last_checkin"]:
            return False
        last = datetime.fromisoformat(state["last_checkin"])
        deadline = last + timedelta(hours=state["interval_hours"] + state["grace_hours"])
        return datetime.now(UTC) > deadline

    def status(self) -> dict:
        """Get current status for display."""
        state = self._load_state()
        result = {
            "armed": state["armed"],
            "interval_hours": state["interval_hours"],
            "grace_hours": state["grace_hours"],
            "last_checkin": state["last_checkin"],
            "overdue": self.is_overdue(),
        }
        if state["last_checkin"]:
            last = datetime.fromisoformat(state["last_checkin"])
            next_due = last + timedelta(hours=state["interval_hours"])
            result["next_due"] = next_due.isoformat()
        return result

    def _send_warning(self, message: str) -> None:
        """Send a warning via webhook and/or local file."""
        from soosef.config import SoosefConfig

        config = SoosefConfig.load()
        webhook = getattr(config, "deadman_warning_webhook", None)

        # Always write warning to a local file
        warning_file = self._state_file.parent / "WARNING_DEADMAN_OVERDUE"
        warning_file.write_text(f"{datetime.now(UTC).isoformat()}: {message}\n")
        logger.warning("Dead man's switch WARNING: %s", message)

        if webhook:
            try:
                from urllib.parse import urlparse

                parsed = urlparse(webhook)
                hostname = parsed.hostname or ""
                # Block private/internal targets to prevent SSRF
                blocked = hostname in ("localhost", "127.0.0.1", "::1", "0.0.0.0")
                blocked = blocked or hostname.startswith(("10.", "172.16.", "192.168.", "169.254."))
                if blocked:
                    logger.warning("Webhook blocked: internal/private URL %s", hostname)
                else:
                    import urllib.request

                    data = json.dumps({"text": message}).encode()
                    req = urllib.request.Request(
                        webhook, data=data, headers={"Content-Type": "application/json"}
                    )
                    urllib.request.urlopen(req, timeout=10)
                    logger.info("Deadman warning sent to webhook")
            except Exception as e:
                logger.error("Failed to send deadman webhook: %s", e)

    def check(self) -> None:
        """Run the check loop (called by systemd timer or background thread).

        Warning is sent during the grace period. Purge fires only after
        grace expires.
        """
        if self.should_fire():
            logger.warning("DEAD MAN'S SWITCH EXPIRED — firing killswitch")
            from soosef.fieldkit.killswitch import PurgeScope, execute_purge

            execute_purge(PurgeScope.ALL, reason="deadman_expired")
        elif self.is_overdue():
            state = self._load_state()
            last = datetime.fromisoformat(state["last_checkin"])
            grace_deadline = last + timedelta(
                hours=state["interval_hours"] + state["grace_hours"]
            )
            remaining = grace_deadline - datetime.now(UTC)
            mins = max(0, int(remaining.total_seconds() / 60))
            self._send_warning(
                f"Check-in overdue! Killswitch fires in {mins} minutes. "
                f"Run 'soosef fieldkit checkin' immediately."
            )
