"""
Onboarding Guide — answers "where do I start in this project?"

Generates a structured reading order for a new developer based on:
  1. Entry points  — files nobody imports (top of the call stack)
  2. Architecture layers — derived from dependency depth
  3. Hub modules   — most imported (must understand early)
  4. Git activity  — most active files = most important to know

No LLM needed. Works entirely from the pre-built index.
"""

from __future__ import annotations

from collections import deque
from dataclasses import dataclass, field
from pathlib import Path

from ..memory.store import KodaraIndex


@dataclass
class OnboardStep:
    order: int
    path: str
    module_name: str
    summary: str
    reason: str           # why start here
    layer: str            # entry / core / foundation / utility
    imports_count: int    # how many things it uses
    used_by_count: int    # how many things use it


@dataclass
class OnboardGuide:
    project_name: str
    total_files: int
    languages: dict[str, int]
    steps: list[OnboardStep]     # ordered reading list
    architecture_summary: str    # one-paragraph overview
    top_contributors: list[dict] # from git data


def generate(index: KodaraIndex) -> OnboardGuide:
    """
    Build a structured onboarding guide from the index.

    Returns:
        OnboardGuide with ordered steps and architecture summary.
    """
    modules = index.modules

    # Count how many modules import each file (in-degree)
    used_by: dict[str, int] = {}
    for mod in modules.values():
        for dep in mod.get("dependencies", []):
            used_by[dep] = used_by.get(dep, 0) + 1

    # Count how many things each file imports (out-degree)
    imports_count: dict[str, int] = {
        path: len(mod.get("dependencies", []))
        for path, mod in modules.items()
    }

    # Assign architectural layer to each module
    layers = _assign_layers(modules, used_by, imports_count)

    # Score each module for reading importance
    scored = _score_modules(modules, used_by, imports_count, layers)

    # Build ordered steps
    steps: list[OnboardStep] = []
    for order, (path, score, reason) in enumerate(scored, start=1):
        mod = modules[path]
        steps.append(OnboardStep(
            order=order,
            path=path,
            module_name=mod.get("module_name", Path(path).stem),
            summary=mod.get("summary", ""),
            reason=reason,
            layer=layers.get(path, "core"),
            imports_count=imports_count.get(path, 0),
            used_by_count=used_by.get(path, 0),
        ))

    # Architecture summary from layer distribution
    arch_summary = _build_arch_summary(index, layers, used_by)

    # Top contributors from git data
    author_commits: dict[str, int] = {}
    for mod in modules.values():
        for author in mod.get("git", {}).get("top_authors", []):
            name = author.get("name", "")
            author_commits[name] = author_commits.get(name, 0) + author.get("commits", 0)

    top_contributors = [
        {"name": n, "commits": c}
        for n, c in sorted(author_commits.items(), key=lambda x: -x[1])[:5]
    ]

    return OnboardGuide(
        project_name=index.display_name,
        total_files=index.file_count,
        languages=index.language_counts,
        steps=steps,
        architecture_summary=arch_summary,
        top_contributors=top_contributors,
    )


# ── Layer assignment ──────────────────────────────────────────────────────────


def _assign_layers(
    modules: dict,
    used_by: dict[str, int],
    imports_count: dict[str, int],
) -> dict[str, str]:
    """
    Assign each module to an architectural layer:
      entry      — nobody imports this, it imports many things (main, CLI, server)
      core       — imported by many AND imports many (business logic hubs)
      foundation — imported by many, imports few (utils, models, config)
      utility    — imported by few, imports few (helpers, constants)
    """
    layers: dict[str, str] = {}
    for path in modules:
        ub = used_by.get(path, 0)
        ic = imports_count.get(path, 0)

        if ub == 0 and ic >= 2:
            layers[path] = "entry"
        elif ub >= 3 and ic >= 2:
            layers[path] = "core"
        elif ub >= 3 and ic < 2:
            layers[path] = "foundation"
        else:
            layers[path] = "utility"

    return layers


# ── Module scoring ────────────────────────────────────────────────────────────


def _score_modules(
    modules: dict,
    used_by: dict[str, int],
    imports_count: dict[str, int],
    layers: dict[str, str],
) -> list[tuple[str, float, str]]:
    """
    Score and order modules for the onboarding reading list.

    Reading order philosophy:
      1. Entry points first — understand how the system starts
      2. Core/hub modules next — understand the load-bearing structure
      3. Foundation modules — understand the building blocks
      4. Utilities last — only if needed
    """
    LAYER_PRIORITY = {"entry": 0, "core": 1, "foundation": 2, "utility": 3}

    scored: list[tuple[str, float, str]] = []

    for path, mod in modules.items():
        layer = layers.get(path, "utility")
        layer_score = LAYER_PRIORITY[layer]

        ub = used_by.get(path, 0)
        ic = imports_count.get(path, 0)

        # Higher = more important to read early
        importance = (ub * 3) + (ic * 1.5)

        # Git activity: recently changed files are important to know
        git = mod.get("git", {})
        commit_count = git.get("commit_count", 0)
        git_bonus = min(commit_count * 0.2, 5)

        # Has a summary = easier to understand, slightly prefer
        has_summary = 1 if mod.get("summary") else 0

        score = importance + git_bonus + has_summary

        reason = _reading_reason(layer, ub, ic, mod)
        scored.append((path, score - layer_score * 100, reason))

    # Sort: layer first (entry → core → foundation → utility), then by score
    scored.sort(key=lambda x: -x[1])

    # Limit to 12 most important steps — more than that overwhelms
    return scored[:12]


def _reading_reason(layer: str, used_by: int, imports: int, mod: dict) -> str:
    if layer == "entry":
        return "Entry point — start here to understand how the system runs"
    if layer == "core" and used_by >= 5:
        return f"Hub module — used by {used_by} others, central to the architecture"
    if layer == "core":
        return f"Core module — connects {imports} dependencies, used by {used_by} modules"
    if layer == "foundation":
        return f"Foundation — used by {used_by} modules, understand before going deeper"
    return "Supporting module"


# ── Architecture summary ──────────────────────────────────────────────────────


def _build_arch_summary(
    index: KodaraIndex,
    layers: dict[str, str],
    used_by: dict[str, int],
) -> str:
    layer_counts = {"entry": 0, "core": 0, "foundation": 0, "utility": 0}
    for layer in layers.values():
        layer_counts[layer] += 1

    langs = ", ".join(index.language_counts.keys())
    top_hubs = sorted(used_by.items(), key=lambda x: -x[1])[:3]
    hub_names = [Path(p).stem for p, _ in top_hubs]

    parts = [
        f"{index.display_name} is a {langs} project with {index.file_count} files.",
        f"Architecture: {layer_counts['entry']} entry point(s), "
        f"{layer_counts['core']} core module(s), "
        f"{layer_counts['foundation']} foundation module(s), "
        f"{layer_counts['utility']} utilities.",
    ]
    if hub_names:
        parts.append(f"Key hubs (most imported): {', '.join(hub_names)}.")

    return " ".join(parts)
