"""Analytics engine — computes all metrics from local storage."""
from __future__ import annotations
import time
from collections import defaultdict
from typing import Dict, List, Optional
from .models import Metrics


class Analytics:
    def __init__(self, storage):
        self._storage = storage

    def compute_metrics(self, days: int = 30, domain: Optional[str] = None) -> Metrics:
        rows = self._storage.query(days=days, domain=domain)
        feedback = self._storage.query_feedback(days=days)

        if not rows:
            return Metrics(total=0, period_days=days)

        n = len(rows)
        by_action = defaultdict(int)
        for r in rows:
            by_action[r["action"]] += 1

        # Feedback analysis
        fb_by_decision = {f["decision_id"]: f["was_correct"] for f in feedback}
        answered = [r for r in rows if r["action"] == "answer"]
        unsafe = sum(1 for r in answered
                     if r["id"] in fb_by_decision and not fb_by_decision[r["id"]])
        abstained = [r for r in rows if r["action"] == "abstain"]
        correct_abstain = sum(1 for r in abstained
                              if r["id"] in fb_by_decision and fb_by_decision[r["id"]])

        uar = unsafe / len(answered) if answered else 0.0
        abstain_prec = correct_abstain / len(abstained) if abstained else 1.0

        # Latency
        latencies = sorted(r["latency_ms"] for r in rows if r["latency_ms"] > 0)
        avg_lat = sum(latencies) / len(latencies) if latencies else 0
        p95_lat = latencies[int(len(latencies) * 0.95)] if latencies else 0

        # Confidence
        confs = [r["confidence"] for r in rows]
        avg_conf = sum(confs) / len(confs) if confs else 0
        high_conf = sum(1 for c in confs if c >= 0.80) / n
        low_conf  = sum(1 for c in confs if c < 0.50) / n

        # Feedback
        pos_fb = sum(1 for f in feedback if f["was_correct"])
        fb_rate = pos_fb / len(feedback) if feedback else 0

        answer_rate = by_action["answer"] / n
        clarify_rate = by_action["clarify"] / n
        abstain_rate = by_action["abstain"] / n

        return Metrics(
            total=n, period_days=days,
            answer_count=by_action["answer"],
            clarify_count=by_action["clarify"],
            abstain_count=by_action["abstain"],
            answer_rate=answer_rate,
            clarify_rate=clarify_rate,
            abstain_rate=abstain_rate,
            coverage=answer_rate,
            uar=uar,
            abstain_precision=abstain_prec,
            avg_latency_ms=avg_lat,
            p95_latency_ms=p95_lat,
            avg_confidence=avg_conf,
            high_confidence_rate=high_conf,
            low_confidence_rate=low_conf,
            feedback_count=len(feedback),
            positive_feedback=fb_rate,
        )

    def metrics_by_domain(self, days: int = 30) -> Dict[str, Metrics]:
        rows = self._storage.query(days=days)
        domains = set(r["domain"] for r in rows if r["domain"])
        return {d: self.compute_metrics(days=days, domain=d) for d in domains}

    def metrics_by_language(self, days: int = 30) -> Dict[str, Metrics]:
        rows = self._storage.query(days=days)
        by_lang = defaultdict(list)
        for r in rows:
            by_lang[r.get("language", "unknown")].append(r)
        result = {}
        for lang, lang_rows in by_lang.items():
            n = len(lang_rows)
            by_action = defaultdict(int)
            for r in lang_rows:
                by_action[r["action"]] += 1
            result[lang] = Metrics(
                total=n, period_days=days,
                answer_count=by_action["answer"],
                clarify_count=by_action["clarify"],
                abstain_count=by_action["abstain"],
                answer_rate=by_action["answer"]/n,
                clarify_rate=by_action["clarify"]/n,
                abstain_rate=by_action["abstain"]/n,
                coverage=by_action["answer"]/n,
            )
        return result

    def trends(self, days: int = 30, interval: str = "day") -> List[Dict]:
        rows = self._storage.query(days=days)
        if not rows:
            return []

        interval_secs = {"hour": 3600, "day": 86400, "week": 604800}[interval]
        buckets = defaultdict(lambda: defaultdict(int))

        for r in rows:
            bucket = int(r["timestamp"] // interval_secs) * interval_secs
            buckets[bucket][r["action"]] += 1
            buckets[bucket]["total"] += 1
            buckets[bucket]["latency_sum"] += r.get("latency_ms", 0)

        result = []
        for ts in sorted(buckets):
            b = buckets[ts]
            total = b["total"]
            result.append({
                "timestamp":    ts,
                "total":        total,
                "answer_rate":  b["answer"] / total,
                "clarify_rate": b["clarify"] / total,
                "abstain_rate": b["abstain"] / total,
                "avg_latency":  b["latency_sum"] / total,
            })
        return result

    def error_analysis(self, days: int = 30) -> Dict:
        feedback = self._storage.query_feedback(days=days)
        negative = [f for f in feedback if not f["was_correct"]]
        by_action = defaultdict(int)
        for f in negative:
            by_action[f.get("action", "unknown")] += 1
        return {
            "total_negative":    len(negative),
            "by_action":         dict(by_action),
            "negative_rate":     len(negative)/len(feedback) if feedback else 0,
        }

    def top_abstain_patterns(self, days: int = 30, top_n: int = 10) -> List[Dict]:
        rows = self._storage.query(days=days)
        abstained = [r for r in rows if r["action"] == "abstain"]
        by_type = defaultdict(int)
        for r in abstained:
            key = f"{r['query_type']}_{r.get('language', 'en')}"
            by_type[key] += 1
        return [{"pattern": k, "count": v}
                for k, v in sorted(by_type.items(), key=lambda x: -x[1])[:top_n]]
