"""Nexus — Telegram Bot Notification Module
Sends alerts/recovery/system messages via Telegram Bot API.
"""

import html
import logging
import re
import httpx
from datetime import datetime, timezone

from server.config import settings

logger = logging.getLogger("nexus.telegram")

# Bot API base URL
TELEGRAM_API_BASE = "https://api.telegram.org"

# Reusable httpx client — avoids TCP connection churn during alert storms
_http_client: httpx.AsyncClient | None = None

# F2d-04: never forward raw DB/Redis URLs or credentials to Telegram or logs
_REDACT_PATTERNS: list[tuple[re.Pattern[str], str]] = [
    (re.compile(r"\b(?:mysql|postgresql|redis)(?:\+\w+)?://\S+", re.I), "<connection-url-redacted>"),
    (re.compile(r"\bpassword[=:]\S+", re.I), "password=<redacted>"),
    (re.compile(r"\bBearer\s+\S+", re.I), "Bearer <redacted>"),
    (re.compile(r"\b(?:SECRET|API|ENCRYPTION)_KEY[=:]\S+", re.I), "<key-redacted>"),
]


def sanitize_external_message(text: str, max_len: int = 240) -> str:
    """Strip connection strings and secrets before external notification channels."""
    if not text:
        return ""
    out = text
    for pattern, replacement in _REDACT_PATTERNS:
        out = pattern.sub(replacement, out)
    if len(out) > max_len:
        out = out[: max_len - 3] + "..."
    return out


async def _get_client() -> httpx.AsyncClient:
    global _http_client
    if _http_client is None or _http_client.is_closed:
        _http_client = httpx.AsyncClient(timeout=10.0)
    return _http_client


async def close_client():
    """Close the shared httpx client — call during app shutdown"""
    global _http_client
    if _http_client and not _http_client.is_closed:
        await _http_client.aclose()
    _http_client = None


async def send_telegram(message: str) -> bool:
    """Send a Telegram message via Bot API.

    Returns True if sent successfully, False if skipped or failed.
    Silently skips if TELEGRAM_BOT_TOKEN or TELEGRAM_CHAT_ID is not configured.
    """
    if not settings.TELEGRAM_BOT_TOKEN or not settings.TELEGRAM_CHAT_ID:
        return False  # Not configured — silent skip

    try:
        client = await _get_client()
        resp = await client.post(
            f"{TELEGRAM_API_BASE}/bot{settings.TELEGRAM_BOT_TOKEN}/sendMessage",
            json={
                "chat_id": settings.TELEGRAM_CHAT_ID,
                "text": message,
                "parse_mode": "HTML",
            },
        )
        if resp.status_code == 200:
            logger.info(f"Telegram sent: {sanitize_external_message(message)[:50]}...")
            return True
        else:
            logger.error(f"Telegram API error: {resp.status_code} {resp.text[:100]}")
            return False
    except Exception as e:
        logger.error(f"Telegram send failed: {e}")
        return False


def _notify_enabled(setting_value: str) -> bool:
    """Return True unless the setting is explicitly 'false' / '0' / 'no'."""
    return setting_value.strip().lower() not in ("false", "0", "no", "off")


async def send_telegram_alert(server_name: str, alert_type: str, value: float) -> bool:
    """Send server resource alert — respects per-type notify toggle."""
    # Map alert_type (cpu/mem/disk) to settings toggle
    _toggle_map = {
        "cpu": "NOTIFY_ALERT_CPU",
        "mem": "NOTIFY_ALERT_MEM",
        "disk": "NOTIFY_ALERT_DISK",
    }
    toggle_attr = _toggle_map.get(alert_type.lower(), "NOTIFY_ALERT_CPU")
    if not _notify_enabled(getattr(settings, toggle_attr, "true")):
        logger.debug(f"Alert notification suppressed by toggle: {toggle_attr}")
        return False

    now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
    safe_name = html.escape(server_name)
    safe_type = html.escape(alert_type)
    return await send_telegram(
        f"🔴 <b>告警</b>\n"
        f"服务器 <b>{safe_name}</b> {safe_type} 使用率 <b>{value:.1f}%</b>\n"
        f"时间: {now}"
    )


async def send_telegram_recovery(server_name: str, metric: str, value: float) -> bool:
    """Send server recovery notification — respects NOTIFY_RECOVERY toggle."""
    if not _notify_enabled(settings.NOTIFY_RECOVERY):
        logger.debug("Recovery notification suppressed by toggle: NOTIFY_RECOVERY")
        return False

    now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
    safe_name = html.escape(server_name)
    safe_metric = html.escape(metric)
    return await send_telegram(
        f"🟢 <b>恢复</b>\n"
        f"服务器 <b>{safe_name}</b> {safe_metric} 已恢复正常 ({value:.1f}%)\n"
        f"时间: {now}"
    )


async def send_telegram_system_alert(message: str, notify_key: str = "") -> bool:
    """Send system-level alert.

    notify_key: settings attribute name to check toggle, e.g. 'NOTIFY_SYSTEM_REDIS'.
    If empty, always send (fallback for callers that don't specify).
    """
    if notify_key and not _notify_enabled(getattr(settings, notify_key, "true")):
        logger.debug(f"System alert suppressed by toggle: {notify_key}")
        return False

    now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
    safe_message = html.escape(sanitize_external_message(message))
    return await send_telegram(
        f"⚠️ <b>系统告警</b>\n"
        f"{safe_message}\n"
        f"时间: {now}"
    )


async def send_telegram_restart_success() -> bool:
    """Notify that Python backend has successfully restarted — respects NOTIFY_RESTART."""
    if not _notify_enabled(settings.NOTIFY_RESTART):
        return False
    now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
    return await send_telegram(
        f"🟢 <b>Nexus后端已恢复</b>\n"
        f"Python服务自动重启成功\n"
        f"时间: {now}"
    )


async def send_telegram_restart_failed() -> bool:
    """Notify that Python backend restart failed — respects NOTIFY_RESTART."""
    if not _notify_enabled(settings.NOTIFY_RESTART):
        return False
    now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
    return await send_telegram(
        f"🔴 <b>Nexus后端重启失败！</b>\n"
        f"请人工介入检查\n"
        f"时间: {now}"
    )


async def send_telegram_sync_complete(
    completed: int, failed: int, total: int,
    source_path: str, operator: str,
    failed_servers: list[str] | None = None,
    duration_seconds: int | None = None,
) -> bool:
    """Send push completion notification via Telegram.

    - All success → 🟢 green
    - Partial failure → 🟡 yellow with failed server list
    - All failed → 🔴 red
    """
    if not _notify_enabled(getattr(settings, "NOTIFY_SYNC_COMPLETE", "true")):
        return False

    now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
    safe_source = html.escape(sanitize_external_message(source_path, max_len=80))
    safe_operator = html.escape(operator)

    if failed == 0:
        icon = "🟢"
        title = "推送完成"
    elif failed < total:
        icon = "🟡"
        title = "推送完成（部分失败）"
    else:
        icon = "🔴"
        title = "推送失败"

    lines = [
        f"{icon} <b>{title}</b>",
        f"源路径: <code>{safe_source}</code>",
        f"操作人: {safe_operator}",
        f"成功: {completed} / 失败: {failed} / 总计: {total}",
    ]
    if duration_seconds is not None:
        mins, secs = divmod(duration_seconds, 60)
        if mins > 0:
            lines.append(f"耗时: {mins}分{secs}秒")
        else:
            lines.append(f"耗时: {secs}秒")
    if failed_servers:
        names = [html.escape(n) for n in failed_servers[:10]]
        lines.append(f"失败服务器: {', '.join(names)}")
        if len(failed_servers) > 10:
            lines.append(f"  ...及其他 {len(failed_servers) - 10} 台")
    lines.append(f"时间: {now}")

    return await send_telegram("\n".join(lines))