"""节点 9/9：商品上传模板导出（template_export）——在 seed_shot 之后。

把最终结果导入模板：
  - SPU货号 / SKU货号 = 设计货号（oss_code，前缀+3位计数）
  - 商品名称 = cn_title（多模态标题生成）
  - 英文名称 = en_title
  - 商品轮播图1：SKU 行按颜色路由（该颜色三合一链接），SPU 行随机一张
  - 详情图文（SPU 行）：全部三合一主图链接 + 种草图链接，| 分割

需在 oss_upload / seed_shot 之后运行（图床链接与货号已生成）。
"""
import time
from pathlib import Path
from typing import Any, Dict, List

from graph.paths import project_root, runtime_root
from graph.validate import with_fallback


def _template_out_path(prod_dir: Path, tpl_name: str) -> Path:
    """模板输出路径：默认 {tpl_name}_已填写.xlsx；已存在/被占用则自动换名加序号（同款号多产品不互相覆盖）。"""
    base = prod_dir / f"{tpl_name}_已填写.xlsx"
    try:
        with open(base, "ab"):
            pass
    except OSError:
        pass
    else:
        if not base.exists():
            return base
    for i in range(2, 100):
        cand = prod_dir / f"{tpl_name}_已填写_{i}.xlsx"
        if not cand.exists():
            return cand
    return prod_dir / f"{tpl_name}_已填写_{int(time.time())}.xlsx"


@with_fallback("template_export")
def template_export_node(state: Dict[str, Any]) -> Dict[str, Any]:
    products: List[Dict[str, Any]] = state.get("product") or []
    config = state["config"] or {}
    pcfg = config.get("product") or {}
    output_dir = Path(state["output_dir"])
    errors = list(state.get("errors") or [])
    stats = dict(state.get("stats") or {})

    # 模板写入时机：所有集合/产品（含种草图、OSS）全部完成后才执行本节点
    print(f"[template] 全部集合（{len(products)} 个产品）处理完成，开始统一写入模板…")

    tp = (pcfg.get("template_path") or "").strip()
    if not tp:
        print("[template] 未配置 product.template_path，跳过模板导出")
        return {"stats": stats, "errors": errors}
    if not Path(tp).exists():
        cand = None
        for root in (runtime_root(), project_root()):
            c = root / tp
            if c.exists():
                cand = str(c)
                break
        if cand:
            tp = cand
        else:
            print(f"[template] 模板文件不存在: {tp}")
            return {"stats": stats, "errors": errors}

    # db 路径
    dbp = (pcfg.get("db_path") or "db/spu_sku.db")
    db_path = Path(dbp)
    if not db_path.is_absolute():
        for root in (runtime_root(), project_root()):
            if (root / db_path).exists():
                db_path = root / db_path
                break

    from graph.template_export import export_product
    tdir = (pcfg.get("template_dir") or "").strip() or str(Path(tp).parent)
    prod_dir = output_dir / "product"
    prod_dir.mkdir(parents=True, exist_ok=True)

    exported: List[str] = []
    skipped = 0
    merged_out: Optional[str] = None   # 合并模式：一次任务所有产品填同一个模板
    is_first = True
    for r in products:
        # 失败跳过：合成图（composite/printed）与标题都失败的产品不写进模板
        has_img = bool(r.get("composite_path") or r.get("printed_path"))
        has_title = bool((r.get("cn_title") or "").strip())
        if not (has_img and has_title):
            skipped += 1
            print(f"[template] 跳过失败产品 {r.get('spu_code')}/{r.get('img_code','')}: "
                  f"合成图={'有' if has_img else '无'} 标题={'有' if has_title else '无'}（不写入模板）")
            continue
        sku_codes = [cc.get("sku_code") for cc in (r.get("color_composites") or [])]
        if not sku_codes:
            sku_codes = [r.get("sku_code") or ""]
        try:
            if is_first:
                merged_out = str(_template_out_path(prod_dir, "商品上传"))
            out = export_product(
                db_path, r.get("spu_code", ""), sku_codes, tdir, tp,
                merged_out,
                images=[],
                spu_per_color=True,                        # 每颜色一个独立 SPU 块（单色多 SPU）
                oss_code=r.get("oss_code") or (r.get("color_composites") or [{}])[0].get("code", ""),
                cn_title=r.get("cn_title", ""),
                en_title=r.get("en_title", ""),
                ja_title=r.get("ja_title", ""),
                composite_urls=r.get("color_composites") or [],
                seed_shot_urls=r.get("seed_shot_urls") or [],
                append_to="" if is_first else merged_out,   # 首个产品从模板创建，后续追加合并
                markup_percent=float(pcfg.get("markup_percent") or 0),
            )
            r["template_path"] = str(out)
            exported.append(str(out))
            print(f"[template] 商品上传模板已生成（{len(exported)}/{len(products)} 合并）: {out}")
        except Exception as e:  # noqa: BLE001
            errors.append({"node": "template_export", "type": type(e).__name__,
                           "message": f"模板导出失败 {r.get('spu_code')}: {e}", "trace": ""})
            print(f"[template] 模板导出失败 {r.get('spu_code')}: {e}")
        is_first = False

    stats["template_export"] = {"exported": len(exported)}
    return {"product": products, "errors": errors, "stats": stats}
