# -*- coding: utf-8 -*-
"""M7 (a207-meal-plan-mcp) 纯 core 单测。不依赖 fastmcp，直接 import core。"""
from __future__ import annotations

import os
import sys

sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))

from a207_meal_plan_mcp import core  # noqa: E402

_PASS = 0
_FAIL = 0


def check(name: str, cond: bool, extra: str = "") -> None:
    global _PASS, _FAIL
    if cond:
        _PASS += 1
        print(f"  [PASS] {name}")
    else:
        _FAIL += 1
        print(f"  [FAIL] {name}  {extra}")


def _all_items(plan):
    out = []
    for d in plan["days"]:
        for m in d["meals"]:
            out.extend(m["items"])
    return out


def test_basic_plan_structure():
    plan = core.generate_meal_plan(1500, 40, 1500, 800, 1500, days=3)
    check("天数正确", len(plan["days"]) == 3)
    for d in plan["days"]:
        check(f"第{d['day']}天含4餐", len(d["meals"]) == 4)
        # 餐次汇总之和 ≈ 当日汇总（仅取整误差）
        meal_e = sum(m["totals"]["energy_kcal"] for m in d["meals"])
        check(f"第{d['day']}天 餐次能量和≈日汇总",
              abs(meal_e - d["day_totals"]["energy_kcal"]) < 15, f"{meal_e} vs {d['day_totals']['energy_kcal']}")
    check("整体达成率字段齐全", set(plan["overall_achievement"].keys()) ==
          {"energy_pct", "protein_pct", "potassium_pct", "phosphorus_pct", "sodium_pct"})


def test_energy_close_to_target():
    plan = core.generate_meal_plan(1500, 40, 1500, 800, 1500, days=7)
    avg = core.get_meal_plan_nutrients(plan)
    check("平均能量接近目标(±10%)", abs(avg["energy_kcal"] - 1500) < 150, str(avg))
    check("平均蛋白非负", avg["protein_g"] > 0)


def test_vegetarian_only_veg_proteins():
    plan = core.generate_meal_plan(1500, 40, 1500, 800, 1500, days=7, vegetarian=True)
    veg_names = {f["name"] for f in core._load_foods() if f.get("veg")}
    for it in _all_items(plan):
        if it["cat"] == "protein":
            check(f"素食模式蛋白源为植物性: {it['food']}", it["food"] in veg_names, it["food"])


def test_exclude_foods():
    plan = core.generate_meal_plan(1500, 40, 1500, 800, 1500, days=7, exclude_foods=["鸡蛋", "米饭(熟)"])
    names = {it["food"] for it in _all_items(plan)}
    check("排除食物未出现(鸡蛋)", "鸡蛋" not in names)
    check("排除食物未出现(米饭)", "米饭(熟)" not in names)


def test_recompute_nutrients():
    plan = core.generate_meal_plan(1500, 40, 1500, 800, 1500, days=4)
    recomputed = core.get_meal_plan_nutrients(plan)
    check("重算返回5项营养", set(recomputed.keys()) ==
          {"energy_kcal", "protein_g", "potassium_mg", "phosphorus_mg", "sodium_mg"})


def test_invalid_targets():
    try:
        core.generate_meal_plan(0, 40, 1500, 800, 1500)
        check("能量=0 应抛错", False)
    except ValueError:
        check("能量=0 抛 ValueError", True)
    try:
        core.generate_meal_plan(1500, 40, 1500, 800, 1500, days=0)
        check("days=0 应抛错", False)
    except ValueError:
        check("days=0 抛 ValueError", True)


def main() -> int:
    print("M7 meal-plan 核心测试")
    test_basic_plan_structure()
    test_energy_close_to_target()
    test_vegetarian_only_veg_proteins()
    test_exclude_foods()
    test_recompute_nutrients()
    test_invalid_targets()
    print(f"\n结果: {_PASS} 通过 / {_FAIL} 失败")
    return 1 if _FAIL else 0


if __name__ == "__main__":
    raise SystemExit(main())
