"""冰箱食材管理 API — FastAPI"""
from fastapi import FastAPI, HTTPException, Query
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
from pydantic import BaseModel, Field
from datetime import date, datetime, timedelta
import json
import uuid
import os

from database import get_db, init_db
from seed_data import seed_all
import functools
from fastapi.responses import JSONResponse
import gzip as gzip_module

# ── 静态数据缓存 ──────────────────────────
_static_recipes = None
_static_tips = None

def _get_static_recipes(db):
    global _static_recipes
    if _static_recipes is None:
        recipes = list(db["recipes"].rows)
        for r in recipes:
            r = dict(r)
            r["ingredients"] = json.loads(r["ingredients"])
            r["steps"] = json.loads(r["steps"])
            r["tags"] = json.loads(r["tags"])
            r["ingredient_amounts"] = json.loads(r.get("ingredient_amounts", "[]")) if r.get("ingredient_amounts") else []
            r["step_times"] = json.loads(r.get("step_times", "[]")) if r.get("step_times") else []
            r["pantry_items"] = json.loads(r.get("pantry_items", "[]")) if r.get("pantry_items") else []
            r["recipe_emoji"] = r.get("recipe_emoji", "🍳")
        _static_recipes = recipes
    return _static_recipes

def _get_static_tips(db):
    global _static_tips
    if _static_tips is None:
        _static_tips = [dict(t) for t in db["tips"].rows]
    return _static_tips


app = FastAPI(title="冰箱食材管理", version="1.0.0")
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])

# 前端目录
F_DIR = os.path.join(os.path.dirname(__file__), "..", "frontend")

# ── 启动初始化 ──────────────────────────────

@app.on_event("startup")
def startup():
    init_db()
    seed_all()


# ── 模型 ────────────────────────────────────

class FoodCreate(BaseModel):
    name: str
    category: str = "其他"
    quantity: float = 1
    unit: str = "个"
    purchase_date: str = None
    expiry_date: str = None
    price: float = 0
    storage: str = "冷藏"
    added_by: str = "default"
    barcode: str = ""
    notes: str = ""

class FoodUpdate(BaseModel):
    name: str = None
    category: str = None
    quantity: float = None
    unit: str = None
    expiry_date: str = None
    notes: str = None
    status: str = None

class FamilyCreate(BaseModel):
    name: str
    creator_openid: str

class FamilyJoin(BaseModel):
    invite_code: str
    openid: str
    nickname: str = ""

class ShoppingItem(BaseModel):
    name: str
    quantity: float = 1
    unit: str = "个"
    added_by: str = "default"

class ShoppingUpdate(BaseModel):
    purchased: bool


# ── 家庭组 ──────────────────────────────────

@app.post("/api/family/create")
def create_family(data: FamilyCreate):
    db = get_db()
    fid = uuid.uuid4().hex[:8]
    code = uuid.uuid4().hex[:6]
    db["families"].insert({"id": fid, "name": data.name, "invite_code": code, "created_at": datetime.now().isoformat()})
    # 创建者加入
    db["users"].insert({"openid": data.creator_openid, "family_id": fid, "nickname": "", "avatar_url": "", "created_at": datetime.now().isoformat()}, replace=True)
    return {"family_id": fid, "invite_code": code}

@app.post("/api/family/join")
def join_family(data: FamilyJoin):
    db = get_db()
    rows = list(db["families"].rows_where("invite_code = ?", [data.invite_code]))
    if not rows:
        raise HTTPException(404, "邀请码无效")
    fam = rows[0]
    db["users"].insert({"openid": data.openid, "family_id": fam["id"], "nickname": data.nickname, "avatar_url": "", "created_at": datetime.now().isoformat()}, replace=True)
    return {"family_id": fam["id"], "name": fam["name"]}

@app.put("/api/family/{family_id}/rename")
def rename_family(family_id: str, name: str = Query(...)):
    db = get_db()
    db["families"].update(family_id, {"name": name})
    return {"ok": True}

@app.get("/api/family/{family_id}")
def get_family(family_id: str):
    db = get_db()
    fam = db["families"].get(family_id)
    if not fam:
        raise HTTPException(404, "家庭组不存在")
    members = list(db["users"].rows_where("family_id = ?", [family_id]))
    return {"family": dict(fam), "members": [dict(m) for m in members]}


# ── 食材 CRUD ───────────────────────────────

@app.get("/api/foods")
def list_foods(family_id: str, status: str = None):
    db = get_db()
    if status:
        rows = list(db["foods"].rows_where("family_id = ? AND status = ?", [family_id, status], order_by="expiry_date ASC"))
    else:
        rows = list(db["foods"].rows_where("family_id = ?", [family_id], order_by="expiry_date ASC"))
    return {"foods": [dict(r) for r in rows]}

@app.post("/api/foods")
def add_food(data: FoodCreate, family_id: str = Query(...)):
    db = get_db()
    today = date.today().isoformat()
    expiry = data.expiry_date or today
    status = "fresh"
    if data.expiry_date:
        ed = date.fromisoformat(data.expiry_date)
        td = date.today()
        days_left = (ed - td).days
        if days_left < 0:
            status = "expired"
        elif days_left <= 3:
            status = "expiring"
    fid = db["foods"].insert({
        "family_id": family_id,
        "name": data.name,
        "category": data.category,
        "quantity": data.quantity,
        "unit": data.unit,
        "purchase_date": data.purchase_date or today,
        "expiry_date": expiry,
        "price": data.price,
        "storage": data.storage,
        "added_by": data.added_by,
        "barcode": data.barcode,
        "notes": data.notes,
        "status": status,
        "created_at": datetime.now().isoformat(),
    })
    return {"ok": True, "status": status}

@app.put("/api/foods/{food_id}")
def update_food(food_id: int, data: FoodUpdate):
    db = get_db()
    food = db["foods"].get(food_id)
    if not food:
        raise HTTPException(404, "食材不存在")
    patch = {k: v for k, v in data.model_dump().items() if v is not None}
    if "expiry_date" in patch:
        ed = date.fromisoformat(patch["expiry_date"])
        days_left = (ed - date.today()).days
        if days_left < 0:
            patch["status"] = "expired"
        elif days_left <= 3:
            patch["status"] = "expiring"
        else:
            patch["status"] = "fresh"
    db["foods"].update(food_id, patch)
    return dict(db["foods"].get(food_id))

@app.delete("/api/foods/{food_id}")
def delete_food(food_id: int):
    db = get_db()
    db["foods"].delete(food_id)
    return {"ok": True}

@app.post("/api/foods/{food_id}/consume")
def consume_food(food_id: int):
    db = get_db()
    db["foods"].update(food_id, {"status": "consumed"})
    return dict(db["foods"].get(food_id))


# ── 过期提醒 ────────────────────────────────

@app.get("/api/foods/expiring")
def expiring_foods(family_id: str):
    db = get_db()
    today = date.today()
    soon = today + timedelta(days=3)
    rows = list(db["foods"].rows_where(
        "family_id = ? AND status IN ('fresh','expiring') AND expiry_date <= ?",
        [family_id, soon.isoformat()],
        order_by="expiry_date ASC"
    ))
    expired = list(db["foods"].rows_where(
        "family_id = ? AND status = 'expired'",
        [family_id],
        order_by="expiry_date ASC"
    ))
    return {"expiring": [dict(r) for r in rows], "expired": [dict(r) for r in expired]}


# ── 快照卡片 ────────────────────────────────

@app.get("/api/snapshot")
def snapshot(family_id: str):
    db = get_db()
    foods = list(db["foods"].rows_where("family_id = ? AND status != 'consumed'", [family_id]))
    total = len(foods)
    expiring = sum(1 for f in foods if f["status"] == "expiring")
    expired = sum(1 for f in foods if f["status"] == "expired")
    categories = {}
    for f in foods:
        cat = f["category"] or "其他"
        categories[cat] = categories.get(cat, 0) + 1
    return {
        "total": total,
        "expiring": expiring,
        "expired": expired,
        "categories": categories,
    }


# ── 菜谱推荐 ────────────────────────────────

@app.get("/api/recipes")
def suggest_recipes(family_id: str, limit: int = 30):
    db = get_db()
    foods = list(db["foods"].rows_where(
        "family_id = ? AND status IN ('fresh','expiring')",
        [family_id]
    ))
    food_names = [f["name"] for f in foods]
    food_set = set(food_names)
    conflicts_cache = check_conflicts(db, food_names)

    recipes = _get_static_recipes(db)
    results = []
    for r in recipes:
        ings = r["ingredients"]
        pantry = r.get("pantry_items", [])
        needed = [i for i in ings if i not in pantry]
        matched = [i for i in needed if i in food_set or match_generic(i, food_set)]
        missing = [i for i in needed if i not in food_set and not match_generic(i, food_set)]
        rd = dict(r)
        rd["matched_count"] = len(matched)
        rd["total_count"] = len(needed)
        rd["missing"] = missing
        rd["completeness"] = round(len(matched) / len(needed) * 100) if needed else 100
        rd["can_make"] = len(missing) == 0
        rd["conflicts"] = conflicts_cache
        results.append(rd)

    results.sort(key=lambda x: (-x["can_make"], -x["completeness"]))
    # 只返回 limit 条 + 去掉步骤/食材清单等重字段（详情走独立接口）
    results = results[:max(limit, 5)]
    light_results = []
    for r in results:
        light_results.append({
            "id": r.get("id", 0), "name": r["name"], "description": r["description"],
            "recipe_emoji": r.get("recipe_emoji", "🍳"),
            "tags": r.get("tags", []), "cooking_time": r.get("cooking_time", 0),
            "difficulty": r.get("difficulty", 1),
            "completeness": r["completeness"], "can_make": r["can_make"],
            "missing": r["missing"][:5],  # 只传前5个缺失食材
            "matched_count": r["matched_count"],
            "total_count": r["total_count"],
            "conflicts": [],
        })
    return {"recipes": light_results, "my_ingredients": food_names}

def match_generic(ingredient: str, food_set: set) -> bool:
    """通用食材匹配：叶菜类匹配各种绿叶菜，猪肉匹配猪肉制品等"""
    generic_map = {
        "叶菜类": {"白菜","青菜","菠菜","生菜","油菜","油麦菜","娃娃菜","茼蒿","空心菜","卷心菜","小白菜","大白菜","芹菜","韭菜"},
        "猪肉": {"猪肉","猪肉末","五花肉"},
    }
    if ingredient in generic_map:
        return bool(generic_map[ingredient] & food_set)
    return False

def check_conflicts(db, food_names: list) -> list:
    """检查当前食材之间的相冲关系"""
    conflicts = []
    for i, a in enumerate(food_names):
        for b in food_names[i+1:]:
            row = list(db["food_conflicts"].rows_where(
                "(food_a = ? AND food_b = ?) OR (food_a = ? AND food_b = ?)",
                [a, b, b, a]
            ))
            if row:
                r = dict(row[0])
                r["involved"] = [a, b]
                conflicts.append(r)
    return conflicts


# ── 菜谱详情 ────────────────────────────────

@app.get("/api/recipes/{recipe_id}")
def get_recipe(recipe_id: int):
    db = get_db()
    r = db["recipes"].get(recipe_id)
    if not r:
        raise HTTPException(404, "菜谱不存在")
    r = dict(r)
    r["ingredients"] = json.loads(r["ingredients"])
    r["steps"] = json.loads(r["steps"])
    r["tags"] = json.loads(r["tags"])
    r["ingredient_amounts"] = json.loads(r.get("ingredient_amounts", "[]")) if r.get("ingredient_amounts") else []
    r["step_times"] = json.loads(r.get("step_times", "[]")) if r.get("step_times") else []
    r["pantry_items"] = json.loads(r.get("pantry_items", "[]")) if r.get("pantry_items") else []
    return r


# ── 采购清单 ────────────────────────────────

@app.get("/api/shopping-list")
def list_shopping(family_id: str):
    db = get_db()
    rows = list(db["shopping_list"].rows_where("family_id = ?", [family_id], order_by="purchased ASC, created_at DESC"))
    return {"items": [dict(r) for r in rows]}

@app.post("/api/shopping-list")
def add_shopping(data: ShoppingItem, family_id: str = Query(...)):
    db = get_db()
    sid = db["shopping_list"].insert({
        "family_id": family_id,
        "name": data.name,
        "quantity": data.quantity,
        "unit": data.unit,
        "added_by": data.added_by,
        "purchased": False,
        "created_at": datetime.now().isoformat(),
    })
    return {"id": sid}

@app.put("/api/shopping-list/{item_id}")
def update_shopping(item_id: int, data: ShoppingUpdate):
    db = get_db()
    db["shopping_list"].update(item_id, {"purchased": data.purchased})
    return db["shopping_list"].get(item_id)

@app.delete("/api/shopping-list/{item_id}")
def remove_shopping(item_id: int):
    db = get_db()
    db["shopping_list"].delete(item_id)
    return {"ok": True}

@app.post("/api/shopping-list/from-expiring")
def auto_add_expiring_to_shopping(family_id: str = Query(...)):
    """一键将过期食材加入采购清单"""
    db = get_db()
    today = date.today()
    soon = today + timedelta(days=3)
    rows = list(db["foods"].rows_where(
        "family_id = ? AND status IN ('expiring','expired')",
        [family_id]
    ))
    added = 0
    for f in rows:
        # 避免重复
        exist = list(db["shopping_list"].rows_where(
            "family_id = ? AND name = ? AND purchased = 0",
            [family_id, f["name"]]
        ))
        if not exist:
            db["shopping_list"].insert({
                "family_id": family_id,
                "name": f["name"],
                "quantity": 1,
                "unit": f["unit"],
                "added_by": "system",
                "purchased": False,
                "created_at": datetime.now().isoformat(),
            })
            added += 1
    return {"added": added}


# ── 小贴士 ──────────────────────────────────

@app.get("/api/tips")
def get_tips(category: str = None):
    db = get_db()
    tips = _get_static_tips(db)
    if category:
        tips = [t for t in tips if t["category"] == category]
    return {"tips": tips}


# ── 扫描条形码（mock，返回提示） ────────────

@app.post("/api/scan")
def scan_barcode(barcode: str):
    """模拟扫码：返回提示让用户补充信息"""
    return {
        "barcode": barcode,
        "message": "请补充食材名称和保质期",
        "suggestion": "可在包装上查看保质期，或在名称栏手动输入",
    }


# ── 自动分类 ──────────────────────────────

CATEGORY_KEYWORDS = {
    "蔬菜": ["白菜","青菜","菠菜","生菜","油菜","油麦菜","娃娃菜","茼蒿","空心菜","卷心菜","芹菜","韭菜","西兰花","花菜","菜花",
             "西红柿","番茄","黄瓜","青椒","辣椒","茄子","豆角","四季豆","豇豆","秋葵","苦瓜","冬瓜","南瓜",
             "丝瓜","西葫芦","萝卜","胡萝卜","土豆","洋葱","大蒜","生姜","山药","红薯","芋头","藕","竹笋","芦笋","玉米",
             "葱","姜","蒜","香菜","薄荷","罗勒","紫苏","芥蓝","菜心","豌豆苗","豆芽","韭菜苔","蒜苔","蒜苗","大葱"],
    "水果": ["苹果","梨","橙子","橘子","柚子","柠檬","香蕉","葡萄","草莓","蓝莓","樱桃","芒果","猕猴桃",
             "西瓜","哈密瓜","桃子","李子","杏","榴莲","荔枝","龙眼","柿子","石榴","火龙果","百香果","椰子",
             "牛油果","菠萝","百香果","甘蔗","山竹","杨梅","枇杷","桑葚","无花果","木瓜","释迦"],
    "肉类": ["猪肉","牛肉","羊肉","鸡肉","鸭肉","鹅肉","五花肉","排骨","猪蹄","猪肝","猪肚","猪腰",
             "鸡腿","鸡胸","鸡翅","鸡爪","牛腩","牛腱","牛排","羊排","肉馅","肉末","里脊","梅花肉","腊肉","腊肠","香肠",
             "培根","火腿","午餐肉","肉"],
    "海鲜": ["虾","鱼","螃蟹","虾仁","贝","三文鱼","带鱼","草鱼","鲈鱼","鱿鱼","墨鱼","章鱼","蛤蜊",
             "生蚝","扇贝","海参","鲍鱼","龙虾","皮皮虾","鳕鱼","黄花鱼","鲳鱼","鳗鱼","鲫鱼","鲤鱼","黑鱼","海带","紫菜"],
    "蛋奶": ["鸡蛋","鸭蛋","鹅蛋","鹌鹑蛋","牛奶","酸奶","奶酪","黄油","奶油","炼乳","奶粉",
             "咸鸭蛋","皮蛋","蛋"],
    "豆制品": ["豆腐","豆皮","豆干","豆芽","腐竹","豆浆","豆腐乳","千张","素鸡","面筋","纳豆","豆"],
    "调料": ["盐","糖","酱油","醋","料酒","蚝油","豆瓣酱","甜面酱","番茄酱","辣椒酱","沙茶酱",
             "味精","鸡精","花椒","胡椒","辣椒","八角","桂皮","香叶","孜然","咖喱","淀粉","生粉",
             "香油","芝麻油","老干妈","火锅底料","泡椒","剁椒","豆豉","榨菜","酱"],
    "主食": ["米","面","粉","馒头","包子","饺子","馄饨","汤圆","粽子","年糕","面条","挂面",
             "方便面","面包","吐司","饼干","麦片","燕麦","米饭","面粉","大米","小米","糯米"],
}

@app.get("/api/classify")
def classify_food(name: str = Query(...)):
    """根据食材名自动分类"""
    for cat, keywords in CATEGORY_KEYWORDS.items():
        for kw in keywords:
            if kw in name:
                return {"category": cat, "matched": kw}
    return {"category": "其他", "matched": None}

# ── 周费用报告 ────────────────────────────

@app.get("/api/weekly-report")
def weekly_report(family_id: str):
    """本周费用统计"""
    db = get_db()
    today = date.today()
    week_start = today - timedelta(days=today.weekday())  # Monday
    week_start_str = week_start.isoformat()
    
    foods = list(db["foods"].rows_where(
        "family_id = ? AND purchase_date >= ?",
        [family_id, week_start_str]
    ))
    
    total = sum(f.get("price", 0) or 0 for f in foods)
    by_category = {}
    for f in foods:
        cat = f["category"] or "其他"
        by_category[cat] = by_category.get(cat, 0) + (f.get("price", 0) or 0)
    
    return {
        "week_start": week_start_str,
        "week_end": today.isoformat(),
        "total": round(total, 2),
        "count": len(foods),
        "by_category": by_category,
        "items": [dict(f) for f in foods],
    }

# ── 健康检查 ────────────────────────────────

@app.get("/api/health")
def health():
    return {"status": "ok", "time": datetime.now().isoformat()}

# ── 点菜模式 ──────────────────────────────

class OrderCreate(BaseModel):
    recipe_name: str
    note: str = ""
    requested_by: str = "匿名"

@app.get("/api/orders")
def list_orders(family_id: str):
    db = get_db()
    rows = list(db["orders"].rows_where("family_id = ?", [family_id], order_by="fulfilled ASC, created_at DESC"))
    return {"orders": [dict(r) for r in rows]}

@app.post("/api/orders")
def create_order(data: OrderCreate, family_id: str = Query(...)):
    db = get_db()
    # 防重复
    existing = list(db["orders"].rows_where(
        "family_id = ? AND recipe_name = ? AND fulfilled = 0",
        [family_id, data.recipe_name]
    ))
    if existing:
        raise HTTPException(409, "这道菜已经许愿过了")
    db["orders"].insert({
        "family_id": family_id,
        "recipe_name": data.recipe_name,
        "requested_by": data.requested_by,
        "note": data.note,
        "fulfilled": False,
        "created_at": datetime.now().isoformat(),
    })
    return {"ok": True}

@app.put("/api/orders/{order_id}/fulfill")
def fulfill_order(order_id: int):
    db = get_db()
    db["orders"].update(order_id, {"fulfilled": True})
    return {"ok": True}

@app.delete("/api/orders/{order_id}")
def delete_order(order_id: int):
    db = get_db()
    db["orders"].delete(order_id)
    return {"ok": True}

# ── 采购参考 ──────────────────────────────

@app.get("/api/shopping-suggestions")
def shopping_suggestions(family_id: str):
    """基于已过期食材和点菜记录，推荐采购清单"""
    db = get_db()
    today = date.today()
    # 近期消耗的食材
    consumed = list(db["foods"].rows_where(
        "family_id = ? AND status = 'consumed'", [family_id],
        order_by="created_at DESC", limit=10
    ))
    # 未完成的点菜
    orders = list(db["orders"].rows_where(
        "family_id = ? AND fulfilled = 0", [family_id],
        order_by="created_at DESC", limit=5
    ))
    return {
        "recently_used": [dict(c) for c in consumed],
        "pending_orders": [dict(o) for o in orders],
        "tip": "以上是家人最近用掉的食材和想吃的菜，采购时可以参考",
    }

# ── 保质期建议 ────────────────────────────

SHELF_LIFE = {
    # 蛋奶
    "牛奶": 7, "酸奶": 14, "奶酪": 30, "黄油": 90, "鸡蛋": 21, "咸鸭蛋": 60, "皮蛋": 90,
    # 蔬菜
    "叶菜类": 4, "白菜": 7, "青菜": 4, "菠菜": 3, "生菜": 3, "油麦菜": 3, "娃娃菜": 5,
    "茼蒿": 3, "空心菜": 2, "卷心菜": 10, "芹菜": 7, "韭菜": 3, "西兰花": 5, "花菜": 5,
    "西红柿": 7, "番茄": 7, "黄瓜": 5, "青椒": 7, "辣椒": 7, "茄子": 5, "豆角": 5,
    "四季豆": 5, "荷兰豆": 4, "豇豆": 5, "秋葵": 4, "苦瓜": 5, "冬瓜": 14, "南瓜": 30,
    "丝瓜": 5, "西葫芦": 5, "萝卜": 14, "胡萝卜": 14, "白萝卜": 14,
    "土豆": 30, "洋葱": 30, "大蒜": 60, "生姜": 30, "山药": 30, "红薯": 30, "芋头": 14,
    "藕": 7, "竹笋": 5, "芦笋": 4, "玉米": 7,
    "香菇": 5, "蘑菇": 3, "金针菇": 3, "杏鲍菇": 5, "木耳": 3, "银耳": 3,
    "豆腐": 5, "豆皮": 7, "豆干": 7, "豆芽": 3, "腐竹": 14,
    # 水果
    "苹果": 30, "梨": 14, "橙子": 14, "橘子": 10, "柚子": 30, "柠檬": 30,
    "香蕉": 5, "葡萄": 5, "草莓": 3, "蓝莓": 5, "樱桃": 5, "芒果": 7, "猕猴桃": 7,
    "西瓜": 7, "哈密瓜": 10, "桃子": 5, "李子": 7, "杏": 5, "榴莲": 7, "荔枝": 3, "龙眼": 5,
    "柿子": 7, "石榴": 14, "火龙果": 10, "百香果": 14, "椰子": 30, "牛油果": 7,
    "西红柿": 7,
    # 肉类（冷藏）
    "猪肉": 3, "牛肉": 3, "羊肉": 3, "鸡肉": 2, "鸭肉": 2,
    "五花肉": 3, "排骨": 3, "猪蹄": 3, "鸡腿": 2, "鸡胸肉": 2, "鸡翅": 2,
    "猪肉末": 2, "牛肉末": 2, "肉馅": 2,
    "香肠": 30, "火腿": 30, "培根": 14, "腊肉": 90, "腊肠": 90,
    "午餐肉": 14,
    # 海鲜
    "虾": 2, "鱼": 2, "螃蟹": 2, "虾仁": 2, "贝类": 2, "三文鱼": 2,
    "带鱼": 2, "草鱼": 2, "鲈鱼": 2, "鱿鱼": 2,
    # 主食
    "米饭": 2, "面包": 5, "馒头": 3, "面条": 7, "饺子": 3, "馄饨": 3,
    "汤圆": 30, "粽子": 30, "年糕": 14,
    # 其他
    "粉条": 180, "粉丝": 180, "紫菜": 365, "海带": 180, "木耳干": 365, "银耳干": 365,
    "火锅底料": 365, "豆瓣酱": 365, "酱油": 365, "醋": 365, "料酒": 365, "蚝油": 180,
    "盐": 999, "糖": 999, "味精": 999, "鸡精": 365, "花椒": 365, "干辣椒": 365,
}

@app.get("/api/shelf-life")
def suggest_shelf_life(name: str = Query(...), storage: str = Query("冷藏")):
    """根据食材名和储存方式建议保质期天数"""
    # 冷冻倍数
    frozen_mult = 30 if storage == "冷冻" else 1  # 冷冻约1个月起步
    days = SHELF_LIFE.get(name)
    if days:
        if storage == "冷冻":
            days = max(30, days * 3)  # 冷冻至少30天，按3倍系数
        suggested = (date.today() + timedelta(days=days)).isoformat()
        return {"found": True, "days": days, "suggested_date": suggested}
    for key, val in SHELF_LIFE.items():
        if key in name or name in key:
            d = max(30, val * 3) if storage == "冷冻" else val
            suggested = (date.today() + timedelta(days=d)).isoformat()
            return {"found": True, "days": d, "suggested_date": suggested, "matched": key}
    return {"found": False, "message": "未找到建议，请根据包装或经验填写"}

# ── 单位建议 ──────────────────────────────

UNIT_MAP = {
    "蔬菜": ["斤", "个", "把", "颗", "根"],
    "水果": ["斤", "个", "颗", "串"],
    "肉类": ["斤", "块", "条", "kg"],
    "海鲜": ["斤", "只", "条", "kg"],
    "蛋奶": ["个", "盒", "瓶", "斤"],
    "豆制品": ["块", "盒", "斤", "包"],
    "调料": ["瓶", "包", "袋", "斤", "kg"],
    "主食": ["斤", "kg", "袋", "包", "个"],
    "其他": ["个", "包", "袋", "瓶", "斤"],
}

@app.get("/api/units")
def suggest_units(category: str = Query(...)):
    """根据食材分类建议常用单位"""
    units = UNIT_MAP.get(category, ["个", "斤", "包"])
    return {"units": units}

# ── 每日推荐 ──────────────────────────────

@app.get("/api/daily-recommend")
def daily_recommend(family_id: str):
    db = get_db()
    foods = list(db["foods"].rows_where(
        "family_id = ? AND status IN ('fresh','expiring')",
        [family_id]
    ))
    food_names = [f["name"] for f in foods]
    food_set = set(food_names)
    conflicts_cache = check_conflicts(db, food_names)

    recipes = _get_static_recipes(db)
    scored = []
    for r in recipes:
        ings = r["ingredients"]
        pantry = r.get("pantry_items", [])
        needed = [i for i in ings if i not in pantry]
        matched = [i for i in needed if i in food_set or match_generic(i, food_set)]
        ratio = len(matched) / len(needed) if needed else 1
        # 优先推荐：食材快过期的 + 能做的
        has_expiring = any(f["status"] == "expiring" and f["name"] in ings for f in foods)
        score = ratio * 100 + (10 if has_expiring else 0)
        missing = [i for i in needed if i not in food_set and not match_generic(i, food_set)]
        rdict = dict(r)
        rdict["ingredients"] = ings
        rdict["pantry_items"] = pantry
        rdict["tags"] = r.get("tags", [])
        rdict["completeness"] = round(ratio * 100)
        rdict["missing"] = missing
        rdict["can_make"] = len(missing) == 0
        rdict["score"] = score
        rdict["conflicts"] = conflicts_cache
        scored.append(rdict)

    scored.sort(key=lambda x: -x["score"])
    # 只返轻量字段
    top_all = []
    for r in scored:
        top_all.append({
            "id": r.get("id", 0), "name": r["name"], "description": r["description"],
            "recipe_emoji": r.get("recipe_emoji", "🍳"),
            "tags": r.get("tags", []), "cooking_time": r.get("cooking_time", 0),
            "completeness": r["completeness"], "can_make": r["can_make"],
            "missing": r["missing"][:5],
        })
    # 去重取 top 3
    seen = set()
    top = []
    for r in top_all:
        if r["name"] not in seen:
            seen.add(r["name"])
            top.append(r)
        if len(top) >= 3:
            break
    return {"recommendations": top, "tip": "快过期的食材优先推荐哦"}

# ── 前端静态文件 ────────────────────────────

if os.path.isdir(F_DIR):
    app.mount("/css", StaticFiles(directory=os.path.join(F_DIR, "css")), name="css")
    app.mount("/js", StaticFiles(directory=os.path.join(F_DIR, "js")), name="js")
    app.mount("/icons", StaticFiles(directory=os.path.join(F_DIR, "icons")), name="icons")

    # 简易密码保护（已关闭）
    # PASSWORD = "fridge888"

    from fastapi import Request
    from fastapi.responses import HTMLResponse

    @app.middleware("http")
    async def auth_middleware(request: Request, call_next):
        return await call_next(request)  # 密码已关闭，直接放行

    @app.get("/manifest.json")
    def manifest():
        return FileResponse(os.path.join(F_DIR, "manifest.json"))

    @app.get("/sw.js")
    def sw():
        return FileResponse(os.path.join(F_DIR, "sw.js"), media_type="application/javascript")

    @app.get("/{full_path:path}")
    def spa_fallback(full_path: str = ""):
        # API 请求已经在上面匹配了，这里只处理前端路由
        if full_path.startswith("api/"):
            raise HTTPException(404)
        return FileResponse(os.path.join(F_DIR, "index.html"))
