from __future__ import annotations

from typing import Any, Iterable

from . import project_model
from .program_registry import get_program


# @hook B4 20260804
# Builds program dependency chains from program_registry and exposes missing-upstream checks for the Web bridge.
def resolve_order(program_id: str) -> list[str]:
    visited: set[str] = set()
    visiting: set[str] = set()
    order: list[str] = []

    def visit(current_id: str) -> None:
        if current_id in visited:
            return
        if current_id in visiting:
            raise ValueError(f"dependency cycle detected at {current_id}")
        visiting.add(current_id)
        program = get_program(current_id)
        for dependency in program.dependencies:
            visit(dependency)
        visiting.remove(current_id)
        visited.add(current_id)
        order.append(current_id)

    visit(program_id)
    return order


def get_required(program_id: str, completed_programs: Iterable[str] | None = None) -> list[dict[str, Any]]:
    completed = set(completed_programs or ())
    missing: list[dict[str, Any]] = []
    for upstream_id in resolve_order(program_id):
        if upstream_id == program_id or upstream_id in completed:
            continue
        program = get_program(upstream_id)
        missing.append(
            {
                "programId": upstream_id,
                "name": program.name,
                "module": program.module,
                "status": program.status,
            }
        )
    return missing


def check_dependencies(
    program_id: str,
    project: project_model.ProjectData | None = None,
    *,
    case_id: str = "proposed",
    frequency: float | str = 1.0,
) -> dict[str, Any]:
    completed = (
        project_model.get_completed_programs(project, case_id, frequency)
        if project is not None
        else set()
    )
    required = get_required(program_id, completed)
    order = resolve_order(program_id)
    one_click_order = [item["programId"] for item in required] + [program_id]
    message = "" if not required else f"需先完成 {required[0]['name']}"
    return {
        "ok": True,
        "programId": program_id,
        "ready": not required,
        "required": required,
        "order": order,
        "oneClickOrder": one_click_order,
        "message": message,
    }


def one_click_plan(
    program_id: str,
    project: project_model.ProjectData | None = None,
    *,
    case_id: str = "proposed",
    frequency: float | str = 1.0,
) -> list[str]:
    return list(check_dependencies(program_id, project, case_id=case_id, frequency=frequency)["oneClickOrder"])
