"""WebSocket + Telegram notifications for script execution progress."""

from __future__ import annotations

import json
import logging
from typing import Any, Optional

from server.config import settings
from server.domain.repositories import ScriptExecutionRepository, ScriptRepository
from server.infrastructure.redis import script_execution_store as ses

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


def _script_board_url(execution_id: int) -> str:
    base = (settings.API_BASE_URL or "").strip().rstrip("/")
    if not base:
        return f"/app/#/script-runs/{execution_id}"
    return f"{base}/app/#/script-runs/{execution_id}"


async def _resolve_label(
    live: dict[str, Any],
    script_repo: Optional[ScriptRepository] = None,
) -> str:
    label = (live.get("label") or "").strip()
    if label:
        return label
    script_id = live.get("script_id")
    if script_id and script_repo:
        script = await script_repo.get_by_id(int(script_id))
        if script and script.name:
            return script.name
    cmd = str(live.get("command") or "")
    if cmd.startswith("[long_task] "):
        cmd = cmd[len("[long_task] "):]
    if len(cmd) > 48:
        return cmd[:48] + "…"
    return cmd or f"执行 #{live.get('id')}"


def _ws_payload(live: dict[str, Any], label: str) -> dict[str, Any]:
    results = live.get("results") or {}
    server_ids = live.get("server_ids") or []
    stats = ses.execution_progress_stats(results, server_ids)
    return {
        "execution_id": int(live["id"]),
        "label": label,
        "status": live.get("status") or "running",
        "long_task": bool(live.get("long_task")),
        "operator": live.get("operator") or "",
        "script_id": live.get("script_id"),
        **stats,
    }


async def notify_script_progress(
    live: dict[str, Any],
    *,
    script_repo: Optional[ScriptRepository] = None,
) -> None:
    """Broadcast running progress (throttle at caller for per-server updates)."""
    try:
        from server.api.websocket import broadcast_script_progress

        label = await _resolve_label(live, script_repo)
        await broadcast_script_progress(_ws_payload(live, label))
    except Exception as e:
        logger.warning("script progress notify failed: %s", e)


async def notify_script_complete(
    live: dict[str, Any],
    *,
    script_repo: Optional[ScriptRepository] = None,
) -> None:
    """Broadcast terminal state + optional Telegram summary."""
    status = live.get("status") or ""
    if status not in ses.TERMINAL_STATUSES:
        return
    try:
        from server.api.websocket import broadcast_script_complete

        label = await _resolve_label(live, script_repo)
        payload = _ws_payload(live, label)
        await broadcast_script_complete(payload)

        from server.infrastructure.telegram import send_telegram_script_summary

        results = live.get("results") or {}
        server_ids = live.get("server_ids") or []
        stats = ses.execution_progress_stats(results, server_ids)
        await send_telegram_script_summary(
            execution_id=int(live["id"]),
            script_label=label,
            operator=str(live.get("operator") or "admin"),
            status=status,
            success_count=int(stats["success"]),
            failed_count=int(stats["failed"]),
            total=int(stats["total"]),
            board_url=_script_board_url(int(live["id"])),
        )
    except Exception as e:
        logger.warning("script complete notify failed: %s", e)


async def notify_script_complete_for_execution(
    execution_repo: ScriptExecutionRepository,
    execution_id: int,
    *,
    script_repo: Optional[ScriptRepository] = None,
) -> None:
    view = await ses.get_execution_view(execution_repo, execution_id)
    if not view:
        return
    raw_ids = view.get("server_ids")
    if isinstance(raw_ids, str):
        try:
            server_ids = json.loads(raw_ids or "[]")
        except json.JSONDecodeError:
            server_ids = []
    else:
        server_ids = raw_ids or []
    live = {
        "id": view["id"],
        "script_id": view.get("script_id"),
        "command": view.get("command"),
        "server_ids": server_ids,
        "status": view.get("status"),
        "results": view.get("results") or {},
        "operator": view.get("operator"),
        "long_task": view.get("long_task", False),
        "label": view.get("label"),
    }
    await notify_script_complete(live, script_repo=script_repo)

