import json
from collections import defaultdict
from datetime import datetime
from pathlib import Path
from typing import Dict, List

from tools import storage

from .utils import increment, log_event

ROOT = Path(__file__).resolve().parents[1]
COHORTS_DIR = ROOT / "artifacts" / "cohorts"
DATA_DIR = ROOT / "samples" / "data"


def define_cohort(name: str, criteria: Dict[str, str]) -> None:
    path = COHORTS_DIR / f"{name}.json"
    storage.write(str(path), criteria)


def _period(ts: str, window: str) -> str:
    dt = datetime.fromisoformat(ts)
    if window == "M":
        return dt.strftime("%Y-%m")
    if window == "W":
        return f"{dt.isocalendar().year}-W{dt.isocalendar().week:02d}"
    if window == "Q":
        q = (dt.month - 1) // 3 + 1
        return f"{dt.year}-Q{q}"
    raise ValueError("unknown window")


METRIC_FUNCS = {
    "revenue": lambda rows: sum(r["revenue"] for r in rows),
    "gross_margin_pct": lambda rows: (
        round(
            (sum(r["revenue"] - r["cost"] for r in rows) / revenue_sum * 100)
            if (revenue_sum := sum(r["revenue"] for r in rows))
            else 0,
            2,
        )
    ),
    "nps": lambda rows: round(sum(r["nps"] for r in rows) / len(rows), 2),
    "return_rate": lambda rows: round(sum(r["return_rate"] for r in rows) / len(rows), 4),
    "uptime": lambda rows: round(sum(r["uptime"] for r in rows) / len(rows), 3),
    "mttr": lambda rows: round(sum(r["mttr"] for r in rows) / len(rows), 2),
}


def cohort_view(table: str, cohort_name: str, metrics: List[str], window: str) -> List[Dict[str, float]]:
    criteria = json.loads(storage.read(str(COHORTS_DIR / f"{cohort_name}.json")))
    rows = json.loads(Path(DATA_DIR / f"{table}.json").read_text())
    filtered = [r for r in rows if all(r.get(k) == v for k, v in criteria.items())]
    buckets: Dict[str, List[Dict]] = defaultdict(list)
    for r in filtered:
        buckets[_period(r["date"], window)].append(r)
    out: List[Dict[str, float]] = []
    for period, bucket in sorted(buckets.items()):
        rec = {"period": period}
        for m in metrics:
            rec[m] = METRIC_FUNCS[m](bucket)
        out.append(rec)
    increment("cohort_run")
    log_event({"type": "cohort_run", "cohort": cohort_name, "table": table})
    return out
