from __future__ import annotations

from dataclasses import dataclass, field
from typing import Literal
import networkx as nx

from .learning_graph import MergedLearningGraph

NodeStatus = Literal["mastered", "ready", "blocked", "hidden"]


@dataclass
class LearnerProfile:
    learner_id: str
    display_name: str = ""
    goals: list[str] = field(default_factory=list)
    mastered_concepts: set[str] = field(default_factory=set)
    hide_mastered: bool = True


@dataclass
class AdaptivePlan:
    node_status: dict[str, NodeStatus] = field(default_factory=dict)
    learner_roadmap: list[dict] = field(default_factory=list)
    next_best_concepts: list[str] = field(default_factory=list)
    eligible_projects: list[dict] = field(default_factory=list)


def classify_node_status(merged: MergedLearningGraph, profile: LearnerProfile) -> dict[str, NodeStatus]:
    status = {}
    for concept_key in nx.topological_sort(merged.graph):
        if concept_key in profile.mastered_concepts:
            status[concept_key] = "hidden" if profile.hide_mastered else "mastered"
            continue
        prereqs = set(merged.graph.predecessors(concept_key))
        status[concept_key] = "ready" if prereqs.issubset(profile.mastered_concepts) else "blocked"
    return status


def build_adaptive_plan(merged: MergedLearningGraph, profile: LearnerProfile, next_limit: int = 5) -> AdaptivePlan:
    status = classify_node_status(merged, profile)
    roadmap = []
    for concept_key in nx.topological_sort(merged.graph):
        state = status[concept_key]
        if state == "hidden":
            continue
        data = merged.concept_data[concept_key]
        roadmap.append({
            "concept_key": concept_key,
            "title": data["title"],
            "pack": data["pack"],
            "status": state,
            "prerequisites": list(merged.graph.predecessors(concept_key)),
        })

    eligible = [
        p for p in merged.project_catalog
        if set(p["prerequisites"]).issubset(profile.mastered_concepts)
    ]

    def ready_priority(concept_key: str) -> tuple[int, int, str]:
        prereqs = list(merged.graph.predecessors(concept_key))
        mastered_prereqs = sum(1 for prereq in prereqs if prereq in profile.mastered_concepts)
        return (0 if mastered_prereqs else 1, -mastered_prereqs, concept_key)

    next_best = sorted((k for k, s in status.items() if s == "ready"), key=ready_priority)[:next_limit]
    return AdaptivePlan(status, roadmap, next_best, eligible)
