"""
alert_ingest.py — Alert ingestion business logic.

Handles:
  - AlertEvent validation and normalization
  - Dedupe-aware ingestion via AlertStore
  - list/get/ack helpers used by alert_ingest_tool handler
"""
from __future__ import annotations

import hashlib
import re
import logging
from typing import Any, Dict, List, Optional

from alert_store import (
    AlertStore,
    _compute_dedupe_key,
    _redact_text,
    _sanitize_alert,
    MAX_LOG_SAMPLES,
)

logger = logging.getLogger(__name__)

# ─── Validation ────────────────────────────────────────────────────────────────

VALID_SEVERITIES = {"P0", "P1", "P2", "P3", "INFO"}
VALID_KINDS = {
    "slo_breach", "crashloop", "latency", "error_rate",
    "disk", "oom", "deploy", "security", "custom",
}
VALID_ENVS = {"prod", "staging", "dev", "any"}


def validate_alert(data: Dict) -> Optional[str]:
    """Return error string or None if valid."""
    if not data.get("service"):
        return "alert.service is required"
    if not data.get("title"):
        return "alert.title is required"
    sev = data.get("severity", "P2")
    if sev not in VALID_SEVERITIES:
        return f"alert.severity must be one of {VALID_SEVERITIES}"
    kind = data.get("kind", "custom")
    if kind not in VALID_KINDS:
        return f"alert.kind must be one of {VALID_KINDS}"
    return None


def normalize_alert(data: Dict) -> Dict:
    """Normalize and sanitize alert fields."""
    safe = _sanitize_alert(data)
    safe.setdefault("kind", "custom")
    safe.setdefault("env", "prod")
    safe.setdefault("severity", "P2")
    safe.setdefault("labels", {})
    safe.setdefault("metrics", {})
    safe.setdefault("links", [])
    safe.setdefault("evidence", {})

    ev = safe.get("evidence", {})
    logs = ev.get("log_samples", [])
    safe["evidence"] = {
        **ev,
        "log_samples": [_redact_text(l, 300) for l in logs[:MAX_LOG_SAMPLES]],
    }
    return safe


# ─── Ingest ────────────────────────────────────────────────────────────────────

def ingest_alert(
    store: AlertStore,
    alert_data: Dict,
    dedupe_ttl_minutes: int = 30,
) -> Dict:
    """
    Validate, normalize, and ingest alert with dedupe.
    Returns the store result dict.
    """
    err = validate_alert(alert_data)
    if err:
        return {"accepted": False, "error": err}

    normalized = normalize_alert(alert_data)
    return store.ingest(normalized, dedupe_ttl_minutes=dedupe_ttl_minutes)


# ─── List/Get/Ack ──────────────────────────────────────────────────────────────

def list_alerts(
    store: AlertStore,
    service: Optional[str] = None,
    env: Optional[str] = None,
    window_minutes: int = 240,
    limit: int = 50,
) -> List[Dict]:
    filters = {}
    if service:
        filters["service"] = service
    if env and env != "any":
        filters["env"] = env
    filters["window_minutes"] = window_minutes
    return store.list_alerts(filters, limit=min(limit, 200))


def get_alert(store: AlertStore, alert_ref: str) -> Optional[Dict]:
    return store.get_alert(alert_ref)


def ack_alert(store: AlertStore, alert_ref: str, actor: str, note: str = "") -> Optional[Dict]:
    if not alert_ref:
        return None
    return store.ack_alert(alert_ref, actor, _redact_text(note, 500))


# ─── Dedupe helpers ────────────────────────────────────────────────────────────

def build_dedupe_key(service: str, env: str, kind: str, fingerprint: str = "") -> str:
    return _compute_dedupe_key(service, env, kind, fingerprint)


def map_alert_severity_to_incident(
    alert_severity: str,
    cap: str = "P1",
) -> str:
    """
    Map alert severity to incident severity, applying a cap.
    e.g. alert P0 with cap P1 → P1.
    """
    order = {"P0": 0, "P1": 1, "P2": 2, "P3": 3, "INFO": 4}
    sev = alert_severity if alert_severity in order else "P2"
    cap_val = cap if cap in order else "P1"
    # Take the higher (less critical) of the two
    if order[sev] < order[cap_val]:
        return cap_val
    return sev
