"""Entry point for heartbeat monitoring."""

from __future__ import annotations

import logging
import os
import sys
import time
from pathlib import Path

from heartbeat.alert_dedup import get_redis, should_alert
from heartbeat.checks import run_checks
from heartbeat.config import (
    ALERT_DEDUP_TTL,
    CRITICAL_KEYS,
    DEGRADED_KEYS,
    WARNING_KEYS,
)
from heartbeat.formatter import format_message
from heartbeat.state import load_pending, save_pending
from heartbeat.telegram import delete_expired, push_deadman_switch, send_telegram

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s | %(levelname)-8s | %(name)s | %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S",
)
logger = logging.getLogger("health-heartbeat")


def main() -> int:
    import setproctitle

    setproctitle.setproctitle(
        "odb-health-heartbeat: 5min-timer stathera-audit telegram-alerts"
    )

    token = os.environ.get("OPENDEVIATIONBAR_TELEGRAM_TOKEN", "")
    chat_id = os.environ.get("OPENDEVIATIONBAR_TELEGRAM_CHAT_ID", "90417581")

    if not token:
        logger.error("Telegram not configured — set OPENDEVIATIONBAR_TELEGRAM_TOKEN")
        return 1

    try:
        return _main(token, chat_id)
    except Exception:
        host = os.environ.get("HOSTNAME") or os.uname().nodename
        logger.critical(
            "Unhandled exception in heartbeat — sending emergency alert", exc_info=True
        )
        try:
            import html as _html
            import traceback as _tb

            tb_text = _html.escape(_tb.format_exc()[-1000:])
            send_telegram(
                token,
                chat_id,
                f"🚨 <b>HEARTBEAT CRASHED</b> on {_html.escape(host)}\n\n"
                f"Unhandled exception in health_heartbeat.py — monitoring is down. "
                f"Check journalctl immediately.\n\n<pre>{tb_text}</pre>",
                silent=False,
            )
        except Exception:
            logger.critical("Emergency Telegram alert also failed", exc_info=True)
        return 2


def _main(token: str, chat_id: str) -> int:
    # Step 1: Delete expired healthy messages
    deleted = delete_expired()
    if deleted:
        logger.info("Cleaned up %d expired heartbeat messages", deleted)

    # Step 2: Run health checks and determine 4-tier health level
    results = run_checks()

    def _failed(keys: frozenset[str]) -> list[str]:
        return sorted(k for k in keys if results.get(k) is False)

    critical_failures = _failed(CRITICAL_KEYS)
    warning_failures = _failed(WARNING_KEYS)
    degraded_failures = _failed(DEGRADED_KEYS)

    if critical_failures:
        health_level = "critical"
    elif warning_failures:
        health_level = "warning"
    elif degraded_failures:
        health_level = "degraded"
    else:
        health_level = "healthy"

    # Backward compat: healthy = no critical or warning failures
    healthy = health_level in ("healthy", "degraded")
    results["_health_level"] = health_level

    # Step 3: Alert dedup via Redis (Issue #186)
    failed_checks = critical_failures + warning_failures + degraded_failures
    alert_fingerprint = "|".join(failed_checks) if failed_checks else ""

    redis_client = get_redis() if not healthy else None
    should_send_alert = healthy or should_alert(redis_client, alert_fingerprint)

    if not should_send_alert:
        logger.info(
            "Alert suppressed (duplicate within %ds): %s",
            ALERT_DEDUP_TTL,
            alert_fingerprint,
        )
        message = format_message(results, healthy)
        msg_id = send_telegram(token, chat_id, message, silent=True)
        if msg_id:
            records = load_pending()
            records.append({"message_id": msg_id, "sent_at": time.time()})
            save_pending(records)
        return 0

    # Step 4: Send message
    # CRITICAL: LOUD persistent. WARNING: silent persistent.
    # DEGRADED/HEALTHY: silent ephemeral.
    auto_healed = bool(results.get("auto_healed_pth"))
    message = format_message(results, healthy)
    silent = health_level != "critical" and not auto_healed
    msg_id = send_telegram(token, chat_id, message, silent=silent)

    if not msg_id:
        logger.error("Failed to send heartbeat message")
        return 1

    # Step 5: Track ephemeral messages (healthy + degraded) for auto-deletion
    # Warning and critical messages are persistent — never auto-deleted.
    if health_level in ("healthy", "degraded"):
        records = load_pending()
        records.append({"message_id": msg_id, "sent_at": time.time()})
        save_pending(records)
        logger.info(
            "Heartbeat %s (message_id=%d, %d pending for cleanup)",
            health_level.upper(),
            msg_id,
            len(records),
        )
    else:
        logger.warning(
            "%s heartbeat sent (persistent): %s",
            health_level.upper(),
            ", ".join(failed_checks),
        )
        for check in failed_checks:
            logger.warning("  FAILED: %s", check)

    # Step 6: ntfy dead-man's-switch (Issue #193)
    push_deadman_switch()

    # Step 7: Cleanup old artifacts (keep last 7 days, preserve symlinks)
    artifacts_dir = Path.home() / "opendeviationbar-py" / "artifacts"
    if artifacts_dir.exists():
        cutoff = time.time() - 7 * 86400
        for f in artifacts_dir.glob("*.json"):
            if f.is_symlink():
                continue
            try:
                if f.stat().st_mtime < cutoff:
                    f.unlink(missing_ok=True)
            except OSError:
                logger.debug("failed to clean artifact %s", f, exc_info=True)

    return 0


if __name__ == "__main__":
    sys.exit(main())
