#!/usr/bin/env python3
# Copyright (c) 2026 PULSE Contributors. Proprietary. All rights reserved.
"""Consolidation completeness check — Item 156.

  - Item 156: Memory consolidation completeness check (Consolidation)

After each consolidation run, verify all stages completed; log any skipped.
"""
import logging
from datetime import datetime, timezone
from typing import Dict, Any, List, Optional

log = logging.getLogger("pulse.brain.consolidation_completeness")

# Known consolidation stages (must match _stage_results_99 keys in consolidation_daemon.py)
EXPECTED_STAGES: List[str] = [
    "stage_1_dedup",
    "stage_2_mining",
    "stage_4_graph",
    "stage_5_metacognition",
    "stage_6_prune",
]

# In-memory run log: list of run records
_RUN_LOG: List[Dict[str, Any]] = []
_MAX_RUNS = 100


def record_consolidation_run(
    completed_stages: List[str],
    run_id: Optional[str] = None,
) -> Dict[str, Any]:
    """Record a consolidation run and check for skipped stages.

    Args:
        completed_stages: list of stage names that completed successfully.
        run_id: optional identifier for this run.

    Returns:
        {run_id, completed, skipped, complete, warning, timestamp}
    Fails open (returns minimal result) on any error.
    """
    result: Dict[str, Any] = {
        "run_id": run_id or datetime.now(timezone.utc).isoformat(),
        "completed": [],
        "skipped": [],
        "complete": False,
        "warning": None,
        "timestamp": datetime.now(timezone.utc).isoformat(),
    }
    try:
        completed_set = set(s.lower().strip() for s in completed_stages if s)
        expected_set = set(EXPECTED_STAGES)
        skipped = sorted(expected_set - completed_set)
        complete = len(skipped) == 0

        warning = None
        if skipped:
            warning = (
                f"!! CONSOLIDATION INCOMPLETE: {len(skipped)} stages skipped: "
                + ", ".join(skipped)
            )
            log.warning("Consolidation run %s skipped stages: %s", run_id, skipped)

        result.update({
            "run_id": run_id or result["run_id"],
            "completed": sorted(completed_set),
            "skipped": skipped,
            "complete": complete,
            "warning": warning,
        })

        _RUN_LOG.append(result.copy())
        if len(_RUN_LOG) > _MAX_RUNS:
            _RUN_LOG.pop(0)

    except Exception as exc:
        log.debug("record_consolidation_run failed: %s", exc)

    return result


def get_consolidation_completeness_history() -> List[Dict[str, Any]]:
    """Return the history of consolidation runs (most recent last)."""
    return list(_RUN_LOG)


def get_last_incomplete_run() -> Optional[Dict[str, Any]]:
    """Return the most recent incomplete run, or None if all runs complete."""
    try:
        for run in reversed(_RUN_LOG):
            if not run.get("complete", True):
                return run
    except Exception:
        pass
    return None
