"""
Bus Factor — finds single points of failure in the team.

Algorithm:
  For each file in the index that has git history:
    - collect unique authors from git data
    - if only ONE unique author AND (dependents >= threshold OR file is a hub)
      → this is a bus factor risk
  Risk level by dependents count:
    0        → LOW
    1–2      → MEDIUM
    3–5      → HIGH
    6+       → CRITICAL
"""

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path

from ..memory.store import KodaraIndex

# Files with >= this many dependents qualify even without is_hub
DEPENDENT_THRESHOLD = 1


@dataclass
class BusFactorRisk:
    file: str                   # absolute path
    module_name: str            # stem name
    sole_author: str            # the single author who owns this file
    dependents_count: int       # how many modules depend on it
    commit_count: int           # total commits on this file
    risk_level: str             # LOW / MEDIUM / HIGH / CRITICAL
    is_hub: bool                # True if file is imported by many modules


def _risk_level(dependents_count: int) -> str:
    if dependents_count >= 6:
        return "CRITICAL"
    if dependents_count >= 3:
        return "HIGH"
    if dependents_count >= 1:
        return "MEDIUM"
    return "LOW"


def _hub_threshold(index: KodaraIndex) -> int:
    """Same hub definition as impact analyzer."""
    return max(2, len(index.modules) // 10)


def get_bus_factor(
    index: KodaraIndex,
    dependent_threshold: int = DEPENDENT_THRESHOLD,
) -> list[BusFactorRisk]:
    """
    Identify files at bus factor risk.

    Returns a list of BusFactorRisk sorted by risk level (CRITICAL first)
    then by dependents_count descending.
    """
    # Compute hub threshold and hub set
    hub_thresh = _hub_threshold(index)
    import_counts: dict[str, int] = {}
    for mod in index.modules.values():
        for dep in mod.get("dependencies", []):
            import_counts[dep] = import_counts.get(dep, 0) + 1
    hubs: set[str] = {p for p, c in import_counts.items() if c >= hub_thresh}

    risk_order = {"CRITICAL": 0, "HIGH": 1, "MEDIUM": 2, "LOW": 3}
    risks: list[BusFactorRisk] = []

    for path, mod in index.modules.items():
        git = mod.get("git", {})
        top_authors = git.get("top_authors", [])

        if not top_authors:
            # No git data — skip
            continue

        # Collect unique author names
        unique_authors = {a["name"] for a in top_authors if a.get("name")}
        if len(unique_authors) != 1:
            # Multiple contributors — not a bus factor risk
            continue

        sole_author = next(iter(unique_authors))
        dep_list = mod.get("dependents", [])
        dependents_count = len(dep_list)
        is_hub = path in hubs
        commit_count = git.get("commit_count", 0)

        # Only flag if the file has impact (dependents or is hub)
        if dependents_count < dependent_threshold and not is_hub:
            continue

        level = _risk_level(dependents_count)

        risks.append(BusFactorRisk(
            file=path,
            module_name=mod.get("module_name", Path(path).stem),
            sole_author=sole_author,
            dependents_count=dependents_count,
            commit_count=commit_count,
            risk_level=level,
            is_hub=is_hub,
        ))

    # Sort: CRITICAL first, then by dependents_count desc
    risks.sort(key=lambda r: (risk_order.get(r.risk_level, 9), -r.dependents_count))
    return risks
