"""Memory Health Score — diagnostic scoring and gap detection."""

from __future__ import annotations

from dataclasses import dataclass, field
from datetime import datetime, timedelta, timezone
from typing import Dict, List, Optional

from .store import MemoryStore


@dataclass
class HealthReport:
    """Overall health report for the memory database."""
    overall_score: float  # 0-100
    dimensions: Dict[str, float] = field(default_factory=dict)
    gaps: List[str] = field(default_factory=list)
    suggestions: List[str] = field(default_factory=list)
    stats: Dict = field(default_factory=dict)


def compute_health(
    store: MemoryStore,
    scope: Optional[str] = None,
) -> HealthReport:
    """Compute a health score for the memory database.

    Scores across dimensions:
    - coverage: Do we have enough memories?
    - freshness: Are memories recent?
    - diversity: Do we cover multiple topics/entities?
    - connectivity: Are memories well-linked?
    - persona: Is the user profile filled in?
    """
    nodes = store.list_nodes(scope=scope, min_importance=0.0, limit=1000)
    nodes = [n for n in nodes if n.deleted_at is None]
    db_stats = store.stats()
    persona = store.get_all_persona()

    dimensions: Dict[str, float] = {}
    gaps: List[str] = []
    suggestions: List[str] = []

    # 1. Coverage score (0-100)
    node_count = len(nodes)
    if node_count == 0:
        dimensions["coverage"] = 0
        gaps.append("No memories stored yet")
        suggestions.append("Start by storing some memories with db.memorize()")
    elif node_count < 5:
        dimensions["coverage"] = 20
        gaps.append(f"Only {node_count} memories — too few for useful recall")
        suggestions.append("Add more memories to improve context quality")
    elif node_count < 20:
        dimensions["coverage"] = 50
    elif node_count < 100:
        dimensions["coverage"] = 80
    else:
        dimensions["coverage"] = 100

    # 2. Freshness score (0-100)
    if nodes:
        now = datetime.now(timezone.utc)
        ages_days = [(now - n.timestamp).total_seconds() / 86400 for n in nodes]
        avg_age = sum(ages_days) / len(ages_days)
        recent_count = sum(1 for a in ages_days if a <= 7)
        recent_ratio = recent_count / len(nodes)

        if avg_age <= 3:
            dimensions["freshness"] = 100
        elif avg_age <= 14:
            dimensions["freshness"] = 75
        elif avg_age <= 60:
            dimensions["freshness"] = 50
        else:
            dimensions["freshness"] = 25
            gaps.append(f"Average memory age is {avg_age:.0f} days — consider adding fresh context")

        if recent_ratio < 0.1 and node_count > 5:
            suggestions.append("Most memories are old. Add recent context to stay current.")
    else:
        dimensions["freshness"] = 0

    # 3. Diversity score (0-100)
    if nodes:
        all_entities: set = set()
        all_scopes: set = set()
        type_counts: Dict[str, int] = {}
        for n in nodes:
            all_entities.update(n.entity_tags)
            all_scopes.add(n.context_scope)
            type_counts[n.memory_type] = type_counts.get(n.memory_type, 0) + 1

        entity_count = len(all_entities)
        scope_count = len(all_scopes)

        if entity_count == 0:
            dimensions["diversity"] = 20
            gaps.append("No entity tags found — memories lack topical structure")
            suggestions.append("Add entity tags when memorizing to improve recall precision")
        elif entity_count < 3:
            dimensions["diversity"] = 40
        elif entity_count < 10:
            dimensions["diversity"] = 70
        else:
            dimensions["diversity"] = 100

        if len(type_counts) < 2:
            suggestions.append(
                "All memories are the same type. Consider using corrections and preferences."
            )
    else:
        dimensions["diversity"] = 0

    # 4. Connectivity score (0-100)
    edge_count = db_stats.get("edge_count", 0)
    if node_count > 0:
        edge_ratio = edge_count / node_count
        if edge_ratio >= 2:
            dimensions["connectivity"] = 100
        elif edge_ratio >= 1:
            dimensions["connectivity"] = 75
        elif edge_ratio >= 0.5:
            dimensions["connectivity"] = 50
        elif edge_ratio > 0:
            dimensions["connectivity"] = 30
        else:
            dimensions["connectivity"] = 0
            if node_count > 3:
                gaps.append("No edges between memories — graph is disconnected")
                suggestions.append("Use entities when memorizing to auto-create links")
    else:
        dimensions["connectivity"] = 0

    # 5. Persona score (0-100)
    if persona:
        filled = len(persona)
        if filled >= 4:
            dimensions["persona"] = 100
        elif filled >= 2:
            dimensions["persona"] = 60
        else:
            dimensions["persona"] = 30
    else:
        dimensions["persona"] = 0
        gaps.append("No persona configured")
        suggestions.append("Set up a persona with db.set_persona() for personalized responses")

    # Overall: weighted average
    weights = {
        "coverage": 0.25,
        "freshness": 0.20,
        "diversity": 0.20,
        "connectivity": 0.15,
        "persona": 0.20,
    }
    overall = sum(dimensions.get(k, 0) * w for k, w in weights.items())

    return HealthReport(
        overall_score=round(overall, 1),
        dimensions=dimensions,
        gaps=gaps,
        suggestions=suggestions,
        stats={
            "node_count": node_count,
            "edge_count": edge_count,
            "entity_count": len(all_entities) if nodes else 0,
            "scope_count": len(all_scopes) if nodes else 0,
            "persona_fields": len(persona),
        },
    )


def get_onboarding_questions(store: MemoryStore) -> List[str]:
    """Generate questions to help bootstrap the memory database.

    Returns questions for missing persona fields and empty topic areas.
    """
    questions: List[str] = []
    persona = store.get_all_persona()

    if "name" not in persona:
        questions.append("What's your name or preferred way to be addressed?")
    if "role" not in persona:
        questions.append("What's your current role or job title?")
    if "expertise" not in persona:
        questions.append("What are your main areas of expertise?")
    if "communication_style" not in persona:
        questions.append("How do you prefer responses — concise or detailed?")
    if "preferences" not in persona:
        questions.append("Any tools, frameworks, or approaches you prefer?")
    if "context" not in persona:
        questions.append("What are you currently working on?")

    nodes = store.list_nodes(min_importance=0.0, limit=100)
    if len(nodes) < 3:
        questions.append("Can you share some key decisions or preferences to remember?")

    return questions
