"""
Consolidator Models - Data classes for memory consolidation.

Contains:
- generate_cluster_id: Deterministic cluster ID generation
- Cluster: A group of similar memories
- ConsolidationResult: Result of consolidating one cluster
- ConsolidationReport: Report from a consolidation run
"""

import hashlib
from dataclasses import dataclass, field
from typing import List, Dict, Optional


def generate_cluster_id(memory_ids: List[str]) -> str:
    """
    Generate deterministic cluster ID from member memory IDs.

    Same memories will always produce the same cluster ID, regardless of
    discovery order or sorting. This ensures cluster IDs are stable across
    scans when clusters have identical sizes.

    Args:
        memory_ids: List of memory IDs in the cluster

    Returns:
        Cluster ID like 'cluster_a3f8b2c1' (prefix + 8-char hash)
    """
    sorted_ids = sorted(memory_ids)
    content = "|".join(sorted_ids)
    hash_hex = hashlib.md5(content.encode()).hexdigest()[:8]
    return f"cluster_{hash_hex}"


@dataclass
class Cluster:
    """A cluster of similar memories."""
    id: str
    memory_ids: List[str]
    memories: List[Dict]
    avg_distance: float = 0.0

    @property
    def size(self) -> int:
        return len(self.memory_ids)

    def to_dict(self) -> Dict:
        # Strip vector field from memories for JSON serialization
        memories_without_vectors = []
        for m in self.memories:
            m_copy = {k: v for k, v in m.items() if k != "vector"}
            memories_without_vectors.append(m_copy)

        return {
            "id": self.id,
            "size": self.size,
            "memory_ids": self.memory_ids,
            "memories": memories_without_vectors,
            "avg_distance": self.avg_distance
        }


@dataclass
class ConsolidationResult:
    """Result of consolidating a cluster."""
    cluster_id: str
    decision: str  # "keep_one", "merge", "keep_all"
    kept_id: Optional[str] = None
    merged_memory: Optional[Dict] = None
    deleted_ids: List[str] = field(default_factory=list)
    reasoning: str = ""

    def to_dict(self) -> Dict:
        return {
            "cluster_id": self.cluster_id,
            "decision": self.decision,
            "kept_id": self.kept_id,
            "merged_memory": self.merged_memory,
            "deleted_ids": self.deleted_ids,
            "reasoning": self.reasoning
        }


@dataclass
class ConsolidationReport:
    """Report from a consolidation run."""
    project: str
    timestamp: str
    clusters_found: int
    clusters_processed: int
    consolidated: int
    kept: int
    deleted: int
    results: List[ConsolidationResult] = field(default_factory=list)
    errors: List[str] = field(default_factory=list)

    def to_dict(self) -> Dict:
        return {
            "project": self.project,
            "timestamp": self.timestamp,
            "clusters_found": self.clusters_found,
            "clusters_processed": self.clusters_processed,
            "consolidated": self.consolidated,
            "kept": self.kept,
            "deleted": self.deleted,
            "results": [r.to_dict() for r in self.results],
            "errors": self.errors
        }
