"""
Metrics Builder — Builds system-wide Impact Metrics for Inspector.

PRD §4.3 — Impact Metrics output:
{
    "total_memories":    128,
    "memories_recalled": 42,
    "memories_adopted":  28,
    "workflows_reused":  9,
    "tasks_avoided":     6,
    "tokens_saved":      3200,
    "avg_quality_score": 0.61,
    "promoted_count":    8,
    "suppressed_count":  3,
    "noise_memories":    4
}

PRD calculation logic:
    workflows_reused = count(workflow.adopted == true)
    tasks_avoided    = workflow_reused + no_duplicate_step (simplified)
    tokens_saved     = reused_workflows * avg_workflow_tokens
"""

import time
import logging

logger = logging.getLogger("openmemo.aggregator")

AVG_WORKFLOW_TOKENS = 350   # §4.3 MVP estimate


class MetricsBuilder:
    """
    Builds system-wide impact metrics from all feedback records.

    Usage:
        builder = MetricsBuilder(feedback_store)
        metrics = builder.build()
    """

    def __init__(self, feedback_store):
        self._store = feedback_store

    def build(self) -> dict:
        """PRD §4.3 — Build global impact metrics."""
        t0 = time.time()

        conn = self._store.conn

        # ── Memory aggregate stats ─────────────────────────────────────────────
        row = conn.execute("""
            SELECT
                COUNT(DISTINCT memory_id)        AS total_unique,
                COUNT(*)                         AS total_events,
                SUM(recalled)                    AS total_recalled,
                SUM(injected)                    AS total_injected,
                SUM(adopted)                     AS total_adopted,
                SUM(success)                     AS total_success
            FROM memory_feedback
        """).fetchone()

        total_memories  = row["total_unique"] or 0
        memories_recalled = row["total_recalled"] or 0
        memories_adopted  = row["total_adopted"]  or 0

        # ── Workflow aggregate stats ───────────────────────────────────────────
        wf_row = conn.execute("""
            SELECT
                COUNT(*)       AS total_wf_events,
                SUM(adopted)   AS workflows_reused,
                SUM(success)   AS workflows_succeeded,
                COUNT(DISTINCT workflow_id) AS unique_workflows
            FROM workflow_feedback
        """).fetchone()

        workflows_reused    = wf_row["workflows_reused"] or 0
        workflows_succeeded = wf_row["workflows_succeeded"] or 0
        unique_workflows    = wf_row["unique_workflows"] or 0

        # §4.3 derived
        tasks_avoided = workflows_reused   # MVP: 1 reuse ≈ 1 task avoided
        tokens_saved  = int(workflows_reused * AVG_WORKFLOW_TOKENS)

        # ── Quality profile stats ──────────────────────────────────────────────
        q_row = conn.execute("""
            SELECT
                COUNT(*)                                    AS total_profiles,
                AVG(quality_score)                          AS avg_quality,
                SUM(CASE WHEN quality_score >= 0.7 THEN 1 ELSE 0 END) AS high_quality,
                SUM(archive_candidate)                      AS archive_candidates,
                SUM(CASE WHEN noise_count >= 5 AND
                     CAST(adoption_count AS REAL) /
                     NULLIF(usage_count, 0) < 0.2 THEN 1 ELSE 0 END) AS suppressed,
                SUM(CASE WHEN
                     CAST(adoption_count AS REAL) /
                     NULLIF(usage_count, 0) >= 0.7 AND
                     CAST(success_count  AS REAL) /
                     NULLIF(adoption_count, 0) >= 0.7 AND
                     usage_count >= 5 THEN 1 ELSE 0 END) AS promoted
            FROM memory_quality_profiles
        """).fetchone()

        avg_quality     = round(q_row["avg_quality"] or 0.0, 4)
        promoted_count  = q_row["promoted"] or 0
        suppressed_count = q_row["suppressed"] or 0
        noise_memories  = q_row["archive_candidates"] or 0

        metrics = {
            "total_memories":       total_memories,
            "memories_recalled":    int(memories_recalled),
            "memories_adopted":     int(memories_adopted),
            "workflows_reused":     int(workflows_reused),
            "unique_workflows":     unique_workflows,
            "tasks_avoided":        int(tasks_avoided),
            "tokens_saved":         tokens_saved,
            "avg_quality_score":    avg_quality,
            "promoted_count":       promoted_count,
            "suppressed_count":     suppressed_count,
            "noise_memories":       noise_memories,
            "build_ms":             round((time.time() - t0) * 1000, 1),
        }

        logger.debug("metrics: recalled=%d workflows_reused=%d tokens_saved=%d ms=%.1f",
                     memories_recalled, workflows_reused, tokens_saved,
                     metrics["build_ms"])
        return metrics

    def build_window(self, since_ts: float, until_ts: float = None) -> dict:
        """Build metrics for a specific time window."""
        t0 = time.time()
        until_ts = until_ts or time.time()
        conn = self._store.conn

        row = conn.execute("""
            SELECT
                COUNT(DISTINCT memory_id) AS total_unique,
                SUM(recalled)  AS recalled,
                SUM(adopted)   AS adopted,
                SUM(success)   AS success
            FROM memory_feedback
            WHERE timestamp >= ? AND timestamp <= ?
        """, (since_ts, until_ts)).fetchone()

        wf_row = conn.execute("""
            SELECT SUM(adopted) AS workflows_reused
            FROM workflow_feedback
            WHERE timestamp >= ? AND timestamp <= ?
        """, (since_ts, until_ts)).fetchone()

        workflows_reused = wf_row["workflows_reused"] or 0

        return {
            "window_start": since_ts,
            "window_end": until_ts,
            "total_memories": row["total_unique"] or 0,
            "memories_recalled": row["recalled"] or 0,
            "memories_adopted": row["adopted"] or 0,
            "workflows_reused": int(workflows_reused),
            "tokens_saved": int(workflows_reused * AVG_WORKFLOW_TOKENS),
            "build_ms": round((time.time() - t0) * 1000, 1),
        }
