from __future__ import annotations

from dataclasses import asdict, dataclass, replace
from typing import Iterable


STATUS_DONE = "已接入"
STATUS_CONNECTING = "接入中"
STATUS_DISABLED = "未启用"

TYPE_FLOW = "流程型"
TYPE_TOOL = "工具型"


@dataclass(frozen=True)
class ProgramModule:
    key: str
    name: str
    category: str
    description: str
    color: str


@dataclass(frozen=True)
class ProgramSpec:
    program_id: str
    module_key: str
    module: str
    name: str
    program_type: str
    inputs: tuple[str, ...]
    outputs: tuple[str, ...]
    dependencies: tuple[str, ...] = ()
    status: str = STATUS_DONE
    source: str = "软件内置"

    def to_dict(self) -> dict[str, object]:
        return asdict(self)


MODULES: tuple[ProgramModule, ...] = (
    ProgramModule("1", "流域水文与设计洪水", "流域水文", "设计暴雨、产汇流、经验公式、单位线、面积比拟、双对数内插和洪水过程复核。", "#1565C0"),
    ProgramModule("2", "灌溉泵站与渠道输水", "灌溉输水", "灌区需水、泵站、压力管道、明渠水力和渠道安全校核。", "#2E7D32"),
    ProgramModule("3", "河道堤防与防洪影响", "河道堤防", "河道演变、堤防、桥涵阻水、壅水、冲刷和涉河影响复核。", "#EF6C00"),
    ProgramModule("4", "水位水面线与断面复核", "水位断面", "曼宁、能量方程、HEC 标准步法和断面水力复核。", "#6A1B9A"),
    ProgramModule("5", "水库蓄水与调洪", "水库大坝", "洪峰洪量、库容、坝顶超高、闸门启闭力和调洪演算。", "#00838F"),
    ProgramModule("6", "水电站压力管道与机电", "水电机电", "水能、装机、压力管道、水锤、输电线路和负荷预测。", "#4527A0"),
    ProgramModule("7", "水工建筑物与桥涵泄流", "水工建筑物", "水闸、堰流、泄槽、消能、渡槽、倒虹吸、隧洞和涵洞。", "#0A5382"),
)


def _p(
    program_id: str,
    module_key: str,
    name: str,
    program_type: str,
    inputs: Iterable[str],
    outputs: Iterable[str],
    dependencies: Iterable[str] = (),
    source: str = "软件内置",
    status: str = STATUS_DONE,
) -> ProgramSpec:
    module = module_by_key(module_key)
    return ProgramSpec(
        program_id=program_id,
        module_key=module_key,
        module=module.name,
        name=name,
        program_type=program_type,
        inputs=tuple(inputs),
        outputs=tuple(outputs),
        dependencies=tuple(dependencies),
        source=source,
        status=status,
    )


def _book(chapter: str, section: str) -> str:
    return f"《水利大算盘》{chapter}{section}"


def module_by_key(key: str) -> ProgramModule:
    for module in MODULES:
        if module.key == key:
            return module
    raise KeyError(f"unknown module key: {key}")


# @hook B2 20260804
# Program registry keeps the independently callable calculation catalog and
# supplies modules/dependencies to the Web UI bridge.  The catalog includes all
# formula programs preserved from the pre-Water-Abacus implementation.
PROGRAMS: tuple[ProgramSpec, ...] = (
    _p("1-01", "1", "流域参数与设计暴雨", TYPE_FLOW, ("流域面积", "主沟长度", "平均比降", "设计频率", "点雨量均值", "Cv/Cs"), ("设计点雨量", "面雨量", "历时选择", "参数表"), source="软件内置洪水计算"),
    _p("1-02", "1", "铁一两所法设计洪水", TYPE_FLOW, ("流域面积", "雨量", "土壤分区", "损失参数", "设计频率"), ("洪峰流量", "参数表", "计算书"), ("1-01",), "软件内置洪水计算"),
    _p("1-03", "1", "地区经验公式洪峰流量", TYPE_FLOW, ("分区", "流域面积", "暴雨参数", "坡降", "形状系数"), ("洪峰流量", "地区参数", "频率系数"), ("1-01",), "软件内置洪水计算"),
    _p("1-04", "1", "瞬时单位线法", TYPE_FLOW, ("雨型分区", "入渗分区", "流域面积", "比降", "1h/6h/24h雨量"), ("面雨量过程", "净雨过程", "单位线", "洪水过程线"), ("1-01",), "软件内置洪水计算"),
    _p("1-05", "1", "推理公式法", TYPE_FLOW, ("流域面积", "坡降", "汇流参数", "设计雨量", "损失参数"), ("汇流曲线", "洪峰流量", "洪水过程线"), ("1-01",), "软件内置洪水计算"),
    _p("1-06", "1", "洪水过程线合成", TYPE_FLOW, ("分区过程线", "汇流时间", "时间步长", "叠加权重"), ("合成过程线", "洪峰", "峰现时间"), ("1-04", "1-05"), "软件内置洪水计算"),
    _p("1-08", "1", "水库洪峰流量和洪水总量", TYPE_FLOW, ("流域面积", "暴雨强度", "汇流参数", "历时"), ("洪峰流量", "洪水总量"), ("1-01",), _book("第五章", "第1节")),
    _p("1-09", "1", "中小河流经验公式法", TYPE_FLOW, ("分区", "面积", "点雨量均值", "面雨量折减系数", "坡降"), ("洪峰流量", "适用时段", "参数说明"), ("1-01",), "软件内置洪水计算"),
    _p("1-10", "1", "设计洪水成果对比", TYPE_TOOL, ("多方法洪峰", "频率", "采用权重", "备注"), ("成果对比表", "采用值建议", "偏差提示"), ("1-02", "1-03", "1-04", "1-05"), "软件内置洪水计算"),
    _p("1-11", "1", "水文面积比拟法", TYPE_FLOW, ("参证站面积", "设计流域面积", "参证站各频率洪峰", "面积指数n"), ("设计流域洪峰", "面积指数n", "外推检查"), source="《水利水电工程设计洪水计算规范》"),
    _p("1-12", "1", "双对数内插法", TYPE_FLOW, ("参证站a/b面积", "参证站a/b各频率洪峰", "设计流域面积"), ("设计流域洪峰", "内插/外推标记", "面积指数n"), source="《水文计算手册》对数内插"),
    _p("1-13", "1", "水文频率适线计算", TYPE_TOOL, ("样本系列", "经验频率", "统计参数Ex/Cv/Cs", "适线准则"), ("理论频率曲线", "各频率设计值", "适线拟合度", "正反向查询"), source="SL 44-2006 附录A"),
    _p("2-01", "2", "引水灌溉灌水模数", TYPE_TOOL, ("灌溉面积", "灌水定额", "延续时间"), ("灌水模数", "作物净流量"), source=_book("第一章", "第1节")),
    _p("2-02", "2", "灌溉引水流量", TYPE_FLOW, ("控制面积", "灌水模数", "干支斗田水利用系数"), ("续灌净流量", "毛流量", "轮灌流量"), ("2-01",), _book("第一章", "第2节")),
    _p("2-03", "2", "灌区渠首水位", TYPE_FLOW, ("最高田面高程", "田面灌水深", "渠道水深", "建筑物损失", "渠道比降长度"), ("渠首设计水位", "逐段水头损失"), ("2-02",), _book("第一章", "第3节")),
    _p("2-04", "2", "提水灌溉设计流量", TYPE_FLOW, ("灌溉面积", "典型年用水量", "灌水率", "利用系数"), ("提水设计流量", "灌溉保证面积"), ("2-01",), _book("第一章", "第4节")),
    _p("2-05", "2", "提灌站压力管道", TYPE_FLOW, ("设计流量", "允许流速", "管材参数", "内压"), ("管径", "最小壁厚", "通气孔面积"), ("2-04",), _book("第一章", "第5节")),
    _p("2-06", "2", "水泵设计扬程", TYPE_FLOW, ("出水池水位", "吸水池水位", "沿程损失", "局部损失"), ("净扬程", "总损失", "设计扬程"), ("2-04",), _book("第一章", "第6节")),
    _p("2-07", "2", "水泵安装高程", TYPE_TOOL, ("允许吸上真空高度", "大气压", "汽化压头", "入口流速", "吸水管损失"), ("允许安装高程", "复核提示"), ("2-06",), _book("第一章", "第7节")),
    _p("2-08", "2", "水泵功率效率及比速", TYPE_TOOL, ("流量", "扬程", "功率", "转速", "效率"), ("有效功率", "总功率", "效率", "比速"), ("2-06",), _book("第一章", "第8节")),
    _p("2-09", "2", "泵站主变压器容量", TYPE_TOOL, ("电机负荷", "照明负荷", "功率因数", "同时系数"), ("主变容量", "标准容量建议"), ("2-08",), _book("第一章", "第9节")),
    _p("3-01", "3", "进水闸引水角度", TYPE_TOOL, ("河道流速", "渠道流速"), ("合理引水角", "适用提示"), source=_book("第二章", "第1节")),
    _p("3-02", "3", "明渠水力", TYPE_FLOW, ("断面形式", "底宽", "水深", "边坡", "糙率", "比降"), ("面积", "湿周", "水力半径", "流速", "流量"), source=_book("第二章", "第2节")),
    _p("3-03", "3", "临界不冲流速", TYPE_TOOL, ("土质类型", "水力半径", "粒径", "护面形式"), ("不冲流速", "设计流速校核"), ("3-02",), _book("第二章", "第3节")),
    _p("3-04", "3", "不淤流速", TYPE_TOOL, ("含沙条件", "流量", "经验系数"), ("不淤流速", "淤积风险提示"), ("3-02",), _book("第二章", "第4节")),
    _p("3-05", "3", "临界水深", TYPE_TOOL, ("断面形式", "流量", "底宽", "边坡"), ("临界水深", "临界流速", "流态判别"), ("3-02",), _book("第二章", "第5节")),
    _p("3-06", "3", "水力最佳断面", TYPE_TOOL, ("断面形式", "设计流量", "糙率", "比降"), ("最佳水深", "底宽", "流量复核"), ("3-02",), _book("第二章", "第6节")),
    _p("3-07", "3", "最佳实用经济断面", TYPE_TOOL, ("面积偏离系数", "断面形式", "流量"), ("经济水深", "经济底宽", "复核流量"), ("3-06",), _book("第二章", "第7节")),
    _p("3-08", "3", "渠道渗漏损失", TYPE_TOOL, ("渠道类型", "长度", "流量", "土壤系数"), ("渗漏损失", "末端流量"), ("3-02",), _book("第二章", "第8节")),
    _p("3-18", "3", "渠道侧墙稳定与配筋校核", TYPE_TOOL, ("填土参数", "墙高", "墙厚", "地下水", "配筋参数"), ("土压力", "墙根弯矩", "所需配筋", "配筋校核"), source="导入前既有渠道侧墙稳定公式"),
    _p("3-19", "3", "复式断面渠道水力计算", TYPE_TOOL, ("总水深", "深槽尺寸", "滩地尺寸", "分区糙率", "底坡"), ("整体法流量", "分块法流量", "各分区流量", "综合糙率"), source="导入前既有复式断面水力公式"),
    _p("3-20", "3", "U形渠道水力计算", TYPE_TOOL, ("水面宽", "水深", "糙率", "底坡"), ("过水面积", "湿周", "水力半径", "流速", "流量"), source="导入前既有 U 形渠道水力公式"),
    _p("3-21", "3", "渠道钢筋工程量与含钢量统计", TYPE_TOOL, ("逐组钢筋规格", "保护层", "间距", "结构长度", "混凝土体积", "损耗率"), ("逐组根数", "长度", "净重", "采购毛重", "含钢量"), source="导入前既有钢筋工程量统计公式"),
    _p("3-22", "3", "渠道纵断面设计高程", TYPE_TOOL, ("桩号", "地面高程", "桩距", "设计底坡", "水深", "超高"), ("逐桩渠底", "最低水位", "设计水位", "渠顶", "挖填高"), source="导入前既有渠道纵断面设计公式"),
    _p("3-23", "3", "河道演变分析", TYPE_TOOL, ("河相", "河宽", "水深", "粒径", "造床流量", "比降"), ("河相关系", "稳定河宽", "纵横向稳定", "冲淤判别"), source="导入前既有河道演变计算程序"),
    _p("3-24", "3", "规范分项冲刷计算", TYPE_TOOL, ("规范公式", "河床/护岸参数", "流量", "流速", "水深", "粒径"), ("中间参数", "分支判别", "冲刷深度/流速", "适用条件"), source="导入前既有规范分项冲刷计算程序"),
    _p("3-25", "3", "桥孔最小净长度计算", TYPE_TOOL, ("河段类型", "设计流量", "河槽/河滩流量", "河宽", "粒径"), ("桥孔最小净长度", "河段系数", "参数代入表", "布设说明"), source="导入前既有桥孔最小净长度计算程序"),
    _p("3-09", "3", "河道流量估算", TYPE_TOOL, ("河宽", "平均水深", "糙率", "比降"), ("河道流速", "河道流量"), source=_book("第三章", "第1节")),
    _p("3-10", "3", "河道治导线宽度", TYPE_TOOL, ("流量", "水深", "糙率", "比降"), ("治导线宽度", "适用提示"), ("3-09",), _book("第三章", "第2节")),
    _p("3-11", "3", "堤顶超高和堤顶高程", TYPE_FLOW, ("设计洪水位", "波浪爬高", "安全加高", "堤身高度"), ("堤顶高程", "超高组成表"), ("4-01",), _book("第三章", "第4节")),
    _p("3-12", "3", "基础埋深安全", TYPE_FLOW, ("现状河床高程", "一般冲刷", "局部冲刷", "基础底高程", "要求埋深"), ("冲刷线高程", "富余埋深", "安全判别"), ("3-14",), "软件内置涉河影响"),
    _p("3-13", "3", "一般冲刷 + 局部冲刷计算", TYPE_FLOW, ("流量", "水深", "流速", "粒径", "桥孔参数"), ("一般冲刷", "局部冲刷", "冲刷线"), ("4-01",), _book("第三章", "第6节")),
    _p("3-14", "3", "壅水曲线与上游回水影响", TYPE_FLOW, ("最大壅水高度", "影响长度", "设计洪水位", "河底坡降", "计算步数"), ("回水曲线", "上游影响范围", "关键断面水位"), ("3-15",), "软件内置涉河影响"),
    _p("3-15", "3", "阻水比/过水面积压缩比计算", TYPE_FLOW, ("天然过水面积", "建后有效面积", "设计流量", "河滩阻挡流量占比"), ("面积阻水比", "流量阻水比", "审查提示"), ("4-01",), "软件内置涉河影响"),
    _p("3-16", "3", "桥前壅水计算", TYPE_FLOW, ("设计流量", "天然流速", "水面坡度", "阻水比", "交角"), ("壅水高度", "影响长度", "桥下平均流速"), ("4-01", "3-15"), "软件内置涉河影响"),
    _p("3-17", "3", "净空校核", TYPE_FLOW, ("设计洪水位", "壅水高度", "安全超高", "梁底高程"), ("计算控制水位", "所需梁底高程", "净空富余", "安全判别"), ("3-16",), "软件内置涉河影响"),
    _p("4-01", "4", "堤防河道水面线推求", TYPE_FLOW, ("断面序列", "流量", "糙率", "比降", "上下游控制水位"), ("逐断面水位", "能坡", "水面线成果"), (), _book("第三章", "第3节")),
    _p("4-02", "4", "单断面曼宁公式水位", TYPE_FLOW, ("断面点", "流量", "糙率", "比降"), ("水位", "面积", "湿周", "流速", "水位流量表"), (), "软件内置水位计算"),
    _p("4-03", "4", "能量方程与 HEC 标准步法", TYPE_FLOW, ("多断面", "流量", "糙率", "局部损失", "控制水位"), ("沿程水面线", "能量坡降", "断面复核表"), (), "软件内置水位计算"),
    _p("4-04", "4", "波浪高度计算", TYPE_TOOL, ("风速", "风区长度", "平均水深", "设计波高频率/系数"), ("平均波高", "设计波高", "波长", "最小风时"), (), "导入前既有水位计算程序"),
    _p("4-05", "4", "风壅水位计算", TYPE_TOOL, ("静水位", "风速", "风区长度", "平均水深", "风向夹角"), ("风壅增水", "叠加水位", "方向折减"), (), "导入前既有水位计算程序"),
    _p("5-01", "5", "水库调洪演算", TYPE_FLOW, ("入库过程线", "水位库容曲线", "水位泄量曲线", "初始水位"), ("出库过程线", "最高水位", "最大下泄", "削峰率"), ("1-08", "1-10"), "软件内置水库调洪"),
    _p("5-02", "5", "水库淤积库容估算", TYPE_TOOL, ("输沙量", "淤积年限", "容重", "拦沙率"), ("淤积库容", "剩余库容"), source=_book("第五章", "第2节")),
    _p("5-03", "5", "水库年运用调节", TYPE_TOOL, ("月来水", "月用水", "蒸发渗漏", "初始库容"), ("逐月库容", "兴利库容", "弃水量"), ("5-02",), _book("第五章", "第3节")),
    _p("5-04", "5", "土石坝坝顶超高", TYPE_TOOL, ("正常水位", "设计水位", "风速", "吹程", "安全加高"), ("风壅", "波浪爬高", "坝顶超高"), ("5-01",), _book("第五章", "第4节")),
    _p("5-05", "5", "土石坝外轮廓尺寸", TYPE_TOOL, ("坝高", "坝顶宽", "上下游边坡", "地基高程"), ("坝体高度", "坝底宽度", "轮廓尺寸"), ("5-04",), _book("第五章", "第5节")),
    _p("5-06", "5", "大坝护坡厚度", TYPE_TOOL, ("波高", "块石容重", "水容重", "边坡"), ("护坡块石尺寸", "护坡厚度"), ("5-04",), _book("第五章", "第6节")),
    _p("5-07", "5", "坝基悬挂帷幕深度", TYPE_TOOL, ("坝高", "地基参数", "经验常数"), ("帷幕深度", "适用提示"), ("5-05",), _book("第五章", "第7节")),
    _p("5-08", "5", "水库库容计算", TYPE_TOOL, ("水位", "断面面积", "层高", "底部锥体参数"), ("分层库容", "总库容", "水位库容表"), source=_book("第五章", "第8节")),
    _p("5-09", "5", "平面闸门启闭力", TYPE_TOOL, ("闸门尺寸", "水头", "摩阻系数", "止水参数"), ("启门力", "闭门力", "启闭机建议"), source=_book("第五章", "第9节")),
    _p("6-01", "6", "水电站水能出力", TYPE_TOOL, ("流量", "水头", "效率", "出力系数"), ("水电站出力", "水轮机功率"), source=_book("第四章", "第1节")),
    _p("6-02", "6", "装机容量计算与选择", TYPE_TOOL, ("保证出力", "年利用小时", "备选容量", "投资参数"), ("装机容量", "经济比较", "推荐方案"), ("6-01",), _book("第四章", "第2节")),
    _p("6-03", "6", "压力管道直径和壁厚", TYPE_TOOL, ("设计流量", "经济流速", "内压", "材料强度"), ("管径", "管壁厚度", "校核结果"), ("6-02",), _book("第四章", "第3节")),
    _p("6-04", "6", "管道进口最小淹没水深", TYPE_TOOL, ("管径", "进口流速", "边界条件"), ("最小淹没水深", "进水口校核"), ("6-03",), _book("第四章", "第4节")),
    _p("6-05", "6", "通气管面积与直径", TYPE_TOOL, ("通气流量", "允许负压", "流速"), ("通气面积", "通气管直径"), ("6-03",), _book("第四章", "第5节")),
    _p("6-06", "6", "压力管道水锤压力", TYPE_TOOL, ("管长", "管径", "流速", "关闭时间", "波速"), ("水锤类型", "水击压力", "允许值复核"), ("6-03",), _book("第四章", "第6节")),
    _p("6-07", "6", "压力管道水头损失", TYPE_TOOL, ("管径", "长度", "糙率", "局部损失系数", "流量"), ("沿程损失", "局部损失", "总损失"), ("6-03",), _book("第四章", "第7节")),
    _p("6-08", "6", "压力钢管抗外压稳定", TYPE_TOOL, ("管壁厚度", "内径", "钢材屈服强度", "弹性模量"), ("明管临界外压", "埋管临界外压"), source="导入前既有压力钢管抗外压稳定公式"),
    _p("6-09", "6", "输电导线经济截面与载流量校核", TYPE_TOOL, ("输送容量", "额定电压", "经济电流密度", "功率因数", "允许温度"), ("经济截面", "持续电流", "推荐导线", "载流量校核"), source="导入前既有输电导线选型公式与 LGJ 载流量表"),
    _p("6-10", "6", "主变压器容量校核", TYPE_TOOL, ("机组总有功功率", "最小负荷", "额定功率因数", "标准容量"), ("所需容量", "标准容量校核"), source="导入前既有主变压器容量公式"),
    _p("6-11", "6", "电力负荷预测与供发电最大负荷", TYPE_TOOL, ("装置功率", "需用系数", "利用小时", "基准负荷", "增长率", "网损", "厂用电率"), ("需用系数法负荷", "增长率法负荷", "供电最大负荷", "发电最大负荷"), source="导入前既有负荷预测公式"),
    _p("7-01", "7", "水闸水力计算", TYPE_TOOL, ("设计流量", "闸孔宽度", "水头", "流量系数"), ("开敞流宽度", "闸室长度", "门槽尺寸"), source=_book("第六章", "第1节")),
    _p("7-02", "7", "溢流堰水力计算", TYPE_TOOL, ("堰型", "流量", "堰宽", "堰顶高程", "上下游水位"), ("堰上水头", "水位", "泄流能力"), ("1-10",), _book("第六章", "第2节")),
    _p("7-03", "7", "正槽式溢洪道泄槽", TYPE_TOOL, ("泄量", "底宽", "坡度", "糙率", "边墙参数"), ("泄槽水深", "掺气水深", "边墙高度"), ("7-02",), _book("第六章", "第3节")),
    _p("7-04", "7", "消力池和海漫", TYPE_TOOL, ("泄量", "上游水深", "下游水深", "单宽流量"), ("共轭水深", "消力池深度", "海漫长度"), ("7-03",), _book("第六章", "第4节")),
    _p("7-05", "7", "陡坡水力", TYPE_TOOL, ("流量", "坡度", "底宽", "糙率", "消能参数"), ("入口宽度", "渐变长度", "泄槽水深"), ("7-04",), _book("第六章", "第5节")),
    _p("7-06", "7", "跌水水力与消能尺寸", TYPE_TOOL, ("流量", "下游渠道底宽", "进口水头", "加大水深", "跌差", "流量系数"), ("入口底宽", "单宽流量", "跌水流量参数", "消力池长度", "消力坎高"), source="导入前既有跌水水力公式"),
    _p("7-07", "7", "引水渡槽水力", TYPE_TOOL, ("槽身流量", "底坡", "糙率", "进出口损失"), ("槽身水深", "速度", "槽底高程", "超高"), ("3-02",), _book("第六章", "第7节")),
    _p("7-08", "7", "倒虹吸管水力", TYPE_TOOL, ("流量", "管径", "管长", "糙率", "局部损失"), ("管径", "水头损失", "管壁厚度", "进出口池"), ("3-02",), _book("第六章", "第8节")),
    _p("7-09", "7", "桥孔水力", TYPE_TOOL, ("设计流量", "桥孔尺寸", "水深", "流速", "净高要求"), ("过流面积", "总净宽", "设计净高", "过桥流量"), ("4-01",), _book("第六章", "第9节")),
    _p("7-10", "7", "隧洞过流断面水力", TYPE_TOOL, ("隧洞工况", "流量", "上游水头", "流量系数", "糙率", "底坡"), ("洞宽", "洞高", "拱圈半径", "圆洞直径", "流量复核"), source="导入前既有隧洞水力公式"),
    _p("7-11", "7", "涵洞泄流断面水力", TYPE_TOOL, ("涵洞工况", "流量", "上游水头", "流量系数", "淹没系数", "高宽比"), ("涵洞宽度", "涵洞高度", "涵内水深", "淹没与非淹没流量"), source="导入前既有涵洞水力公式"),
    _p("7-12", "7", "侧堰分水与泄流能力", TYPE_TOOL, ("分水工况", "流量", "堰宽", "流量系数", "来流流速", "堰上水头"), ("平均堰上水头", "侧堰宽度", "侧堰泄流量"), source="导入前既有侧堰水力公式"),
)


# @hook UI3-3 registry 20260804
# Web UI status is synchronized with real migrated HTML pages; remaining registered programs stay visible as connecting.
# @hook UI59-registry 20260804
# Every registered program has an HTML module page and bridge dispatcher.
HTML_CONNECTED_PROGRAM_IDS = frozenset(program.program_id for program in PROGRAMS)
PROGRAMS = tuple(
    replace(program, status=STATUS_DONE if program.program_id in HTML_CONNECTED_PROGRAM_IDS else STATUS_CONNECTING)
    for program in PROGRAMS
)


PROGRAM_INDEX: dict[str, ProgramSpec] = {program.program_id: program for program in PROGRAMS}


def get_program(program_id: str) -> ProgramSpec:
    try:
        return PROGRAM_INDEX[program_id]
    except KeyError as exc:
        raise KeyError(f"unknown program id: {program_id}") from exc


def list_programs(module_key: str | None = None) -> list[dict[str, object]]:
    programs = PROGRAMS if module_key in (None, "", "all") else tuple(p for p in PROGRAMS if p.module_key == module_key)
    return [program.to_dict() for program in programs]


def list_modules() -> list[dict[str, object]]:
    rows: list[dict[str, object]] = []
    for module in MODULES:
        programs = [program for program in PROGRAMS if program.module_key == module.key]
        flow_count = sum(1 for program in programs if program.program_type == TYPE_FLOW)
        rows.append(
            {
                "key": module.key,
                "name": module.name,
                "category": module.category,
                "description": module.description,
                "color": module.color,
                "program_count": len(programs),
                "flow_count": flow_count,
                "tool_count": len(programs) - flow_count,
                "status_done": sum(1 for program in programs if program.status == STATUS_DONE),
            }
        )
    return rows


def registry_summary() -> dict[str, int]:
    return {
        "total": len(PROGRAMS),
        "flow": sum(1 for program in PROGRAMS if program.program_type == TYPE_FLOW),
        "tool": sum(1 for program in PROGRAMS if program.program_type == TYPE_TOOL),
        "done": sum(1 for program in PROGRAMS if program.status == STATUS_DONE),
        "connecting": sum(1 for program in PROGRAMS if program.status == STATUS_CONNECTING),
        "disabled": sum(1 for program in PROGRAMS if program.status == STATUS_DISABLED),
    }


def dependency_chain_examples() -> list[list[str]]:
    return [
        ["4-01", "3-15", "3-16", "3-17"],
        ["4-01", "3-13", "3-12"],
        ["1-01", "1-04", "1-06", "4-01"],
    ]


def validate_registry() -> None:
    ids = [program.program_id for program in PROGRAMS]
    if len(ids) != len(set(ids)):
        raise ValueError("program registry contains duplicate program_id")
    missing = sorted(
        dependency
        for program in PROGRAMS
        for dependency in program.dependencies
        if dependency not in PROGRAM_INDEX
    )
    if missing:
        raise ValueError(f"program registry contains missing dependencies: {', '.join(missing)}")
    if len(PROGRAMS) != 83:
        raise ValueError(f"program registry must contain 83 programs after restoring the complete historical professional modules, got {len(PROGRAMS)}")


validate_registry()
