"""Slack notification helpers for Autopilot."""

from __future__ import annotations

import os
from typing import TYPE_CHECKING, Any, Dict

from .contracts import PlanV1, ReceiptV1
from .slack_blocks import build_plan_approval_blocks

if TYPE_CHECKING:
    from .briefing import DailyBriefing

try:  # Optional dependency in some environments.
    from slack_sdk import WebClient
except Exception as exc:  # pragma: no cover
    WebClient = None  # type: ignore
    _slack_import_error = exc
else:  # pragma: no cover - no error path when dependency present
    _slack_import_error = None


def _ensure_slack() -> None:
    if WebClient is None:  # pragma: no cover
        raise RuntimeError("slack-sdk is required for Slack notifications.") from _slack_import_error


def create_client(bot_token: str) -> "WebClient":
    _ensure_slack()
    return WebClient(token=bot_token)


def resolve_channel(policy_defaults: Any) -> str | None:
    return policy_defaults.slack_channel or os.getenv("G_GREMLIN_SLACK_CHANNEL")


def post_approval_request(
    web_client: Any,
    channel: str,
    plan: PlanV1,
    approve_token: str,
) -> Dict[str, Any]:
    blocks = build_plan_approval_blocks(plan, approve_token)
    text = f"Autopilot approval required for run {plan.run_id}"
    return web_client.chat_postMessage(channel=channel, text=text, **blocks)


def post_receipt_summary(
    web_client: Any,
    channel: str,
    receipt: ReceiptV1,
) -> Dict[str, Any]:
    changes_count = len(receipt.changes or [])
    blocks = [
        {
            "type": "header",
            "text": {"type": "plain_text", "text": "Autopilot Receipt"},
        },
        {
            "type": "section",
            "text": {
                "type": "mrkdwn",
                "text": (
                    f"*Run:* {receipt.run_id}\n"
                    f"*Outcome:* {receipt.outcome}\n"
                    f"*Changes:* {changes_count}"
                ),
            },
        },
    ]
    text = f"Autopilot run {receipt.run_id} completed: {receipt.outcome}"
    return web_client.chat_postMessage(channel=channel, text=text, blocks=blocks)


def _priority_prefix(priority: int) -> str:
    if int(priority) >= 2:
        return ":warning: "
    if int(priority) == 1:
        return ":exclamation: "
    return ""


def post_briefing(
    web_client: Any,
    channel: str,
    briefing: DailyBriefing,
) -> dict[str, Any]:
    """Post a daily briefing using Slack blocks with truncation safeguards."""

    sections = list(briefing.sections or [])
    blocks: list[dict[str, Any]] = [
        {
            "type": "header",
            "text": {"type": "plain_text", "text": "Autopilot Daily Briefing"},
        },
        {
            "type": "section",
            "text": {"type": "mrkdwn", "text": briefing.summary or "Daily briefing generated."},
        },
        {"type": "divider"},
    ]

    # Reserve one section block for truncation notice if needed.
    max_blocks = 50
    section_blocks_available = max_blocks - len(blocks) - 1
    rendered = 0
    for index, section in enumerate(sections):
        if len(blocks) + 1 > section_blocks_available:
            break
        prefix = _priority_prefix(section.priority)
        body = str(section.body or "").strip() or "- No details."
        blocks.append(
            {
                "type": "section",
                "text": {
                    "type": "mrkdwn",
                    "text": f"*{prefix}{section.title}*\n{body}",
                },
            }
        )
        rendered += 1
        if index < len(sections) - 1 and len(blocks) + 1 <= section_blocks_available:
            blocks.append({"type": "divider"})

    remaining = max(len(sections) - rendered, 0)
    if remaining > 0 and len(blocks) < max_blocks:
        blocks.append(
            {
                "type": "section",
                "text": {
                    "type": "mrkdwn",
                    "text": f"... and {remaining} more items. See Control Tower for full briefing.",
                },
            }
        )

    text = f"Autopilot daily briefing ({briefing.generated_at})"
    return web_client.chat_postMessage(channel=channel, text=text, blocks=blocks[:max_blocks])


def post_anomaly_alert(
    web_client: Any,
    channel: str,
    alerts: list[Any],
) -> dict[str, Any]:
    """Post anomaly alerts to Slack as an urgent summary message."""

    normalized: list[dict[str, Any]] = []
    for alert in alerts or []:
        if isinstance(alert, dict):
            normalized.append(alert)
            continue
        message = str(getattr(alert, "message", "") or "").strip()
        metric_name = str(getattr(alert, "metric_name", "") or "").strip()
        if message or metric_name:
            normalized.append(
                {
                    "metric_name": metric_name,
                    "message": message,
                    "deviation_factor": getattr(alert, "deviation_factor", None),
                }
            )
    if not normalized:
        normalized = [{"metric_name": "unknown", "message": "Anomaly detected."}]

    lines: list[str] = []
    for row in normalized[:8]:
        metric_name = str(row.get("metric_name") or "metric").strip()
        message = str(row.get("message") or "").strip()
        if message:
            lines.append(f"- *{metric_name}*: {message}")
        else:
            lines.append(f"- *{metric_name}* anomaly detected")
    if len(normalized) > 8:
        lines.append(f"- ... and {len(normalized) - 8} more anomaly alerts")

    blocks = [
        {
            "type": "header",
            "text": {"type": "plain_text", "text": "Autopilot Anomaly Alert"},
        },
        {
            "type": "section",
            "text": {"type": "mrkdwn", "text": ":warning: Significant metric deviations detected."},
        },
        {
            "type": "section",
            "text": {"type": "mrkdwn", "text": "\n".join(lines)},
        },
    ]
    return web_client.chat_postMessage(
        channel=channel,
        text="Autopilot anomaly alert",
        blocks=blocks,
    )


__all__ = [
    "create_client",
    "resolve_channel",
    "post_approval_request",
    "post_receipt_summary",
    "post_briefing",
    "post_anomaly_alert",
]
