"""Runtime discrepancy ingestion helpers for Phase 3 hardening."""

from __future__ import annotations

import hashlib
import json
import time as _time
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Dict, List, Tuple


@dataclass
class RuntimeIngestResult:
    status: str
    case_id: str
    event_key: str
    deduped: bool
    file_written: bool
    snowflake_written: bool
    index_updated: bool
    runtime_event_count: int
    runtime_events_path: str
    warning: str = ""

    def to_dict(self) -> Dict[str, Any]:
        payload: Dict[str, Any] = {
            "status": self.status,
            "case_id": self.case_id,
            "event_key": self.event_key,
            "deduped": self.deduped,
            "file_written": self.file_written,
            "snowflake_written": self.snowflake_written,
            "index_updated": self.index_updated,
            "runtime_event_count": self.runtime_event_count,
            "runtime_events_path": self.runtime_events_path,
        }
        if self.warning:
            payload["warning"] = self.warning
        return payload


def validate_runtime_event_shape(event: Dict[str, Any], strict: bool = True) -> Tuple[bool, str]:
    if not isinstance(event, dict):
        return False, "event must be a JSON object"
    if not event:
        return False, "event must not be empty"
    metric = str(event.get("metric") or event.get("metric_name") or "").strip()
    symptom = str(event.get("symptom") or event.get("mismatch") or "").strip()
    source_system = str(event.get("source_system") or event.get("source") or "").strip()
    if not metric or not symptom:
        return False, "event must include metric/metric_name and symptom/mismatch"
    if strict and not source_system:
        return False, "event must include source_system/source in strict mode"
    return True, ""


def _bucket_timestamp(raw_ts: int, window_seconds: int) -> int:
    w = max(60, int(window_seconds or 900))
    return int(raw_ts // w) * w


def derive_event_key(
    *,
    tenant_id: str,
    source_system: str,
    metric: str,
    symptom: str,
    event_ts: int,
    dedupe_window_seconds: int = 900,
) -> str:
    bucket = _bucket_timestamp(event_ts, dedupe_window_seconds)
    token = "|".join(
        [
            (tenant_id or "default").strip().lower(),
            (source_system or "unknown").strip().lower(),
            (metric or "unknown_metric").strip().lower(),
            (symptom or "discrepancy detected").strip().lower(),
            str(bucket),
        ]
    )
    return hashlib.sha256(token.encode("utf-8")).hexdigest()[:32]


def normalize_runtime_event(
    event: Dict[str, Any],
    *,
    tenant_id: str = "default",
    dedupe_window_seconds: int = 900,
) -> Dict[str, Any]:
    source_system = str(event.get("source_system") or event.get("source") or "unknown").strip()
    metric = str(event.get("metric") or event.get("metric_name") or "unknown_metric").strip()
    symptom = str(event.get("symptom") or event.get("mismatch") or "discrepancy detected").strip()
    raw_ts = event.get("timestamp") or event.get("detected_at") or int(_time.time())
    try:
        event_ts = int(float(raw_ts))
    except Exception:
        event_ts = int(_time.time())
    event_key = derive_event_key(
        tenant_id=tenant_id,
        source_system=source_system,
        metric=metric,
        symptom=symptom,
        event_ts=event_ts,
        dedupe_window_seconds=dedupe_window_seconds,
    )

    case_id = str(event.get("case_id") or f"trust_case.runtime.{source_system}.{metric}.{event_key}").strip()
    tags = [str(t).strip().lower() for t in (event.get("tags", []) or []) if str(t).strip()]
    if "reconciliation" not in tags:
        tags.append("reconciliation")

    return {
        "case_id": case_id,
        "event_key": event_key,
        "tenant_id": str(tenant_id or "default").strip() or "default",
        "source_system": source_system,
        "metric": metric,
        "symptom": symptom,
        "lineage_path": event.get("lineage_path", []) or [],
        "root_cause": str(event.get("root_cause", "unknown")).strip(),
        "fix": str(event.get("fix", "pending")).strip(),
        "verification": str(event.get("verification", "pending")).strip(),
        "time_to_closure": str(event.get("time_to_closure", "unknown")).strip(),
        "confidence": float(event.get("confidence", 0.6) or 0.6),
        "tags": tags,
        "event_ts": event_ts,
        "ingested_at": int(_time.time()),
        "metadata": event.get("metadata", {}) if isinstance(event.get("metadata"), dict) else {},
        "raw_event": event,
    }


def append_runtime_event_file(case: Dict[str, Any], runtime_path: Path) -> Tuple[bool, int, bool]:
    """Append to JSON file with idempotent dedupe by event_key/case_id.

    Returns: (inserted, total_rows, file_written)
    """
    runtime_path.parent.mkdir(parents=True, exist_ok=True)
    rows: List[Dict[str, Any]] = []
    if runtime_path.exists():
        try:
            payload = json.loads(runtime_path.read_text(encoding="utf-8"))
            if isinstance(payload, list):
                rows = [r for r in payload if isinstance(r, dict)]
        except Exception:
            rows = []
    existing_keys = {
        str(r.get("event_key", "")).strip() for r in rows if str(r.get("event_key", "")).strip()
    }
    existing_cases = {
        str(r.get("case_id", "")).strip() for r in rows if str(r.get("case_id", "")).strip()
    }
    ek = str(case.get("event_key", "")).strip()
    cid = str(case.get("case_id", "")).strip()
    if (ek and ek in existing_keys) or (cid and cid in existing_cases):
        return False, len(rows), True
    rows.append(case)
    runtime_path.write_text(json.dumps(rows, indent=2), encoding="utf-8")
    return True, len(rows), True
