#!/usr/bin/env python3
"""wx-quote-assistant — 报价单生成器

- HTML: 基于 assets/default_html.html 模板（客户端，无质检内容）
- Excel: 调用 excel_builder.py（客户端，无质检内容）
- QA Report: 基于 assets/default_qa_report.html（内部审批用）
- PDF: weasyprint / wkhtmltopdf 降级

CLI 用法:
  python3 generators.py html --data <full_data.json> --output <path>
  python3 generators.py excel --data <full_data.json> --output <path>
  python3 generators.py qa --data <full_data.json> --output <path>
  python3 generators.py pdf --html <path> --output <path>
  python3 generators.py all --data <json> --out-dir <dir> [--name-prefix <prefix>]
"""

import argparse
import json
import os
import shutil
import subprocess
import sys

# Skill 根目录 (相对 scripts/)
SKILL_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
HTML_TEMPLATE = os.path.join(SKILL_DIR, "assets", "default_html.html")
QA_TEMPLATE = os.path.join(SKILL_DIR, "assets", "default_qa_report.html")


# ── HTML Generator (模板替换模式) ──

def _load_template() -> str:
    """加载 HTML 模板文件。"""
    with open(HTML_TEMPLATE, "r", encoding="utf-8") as f:
        return f.read()


def _build_product_rows(products: list) -> str:
    """生成产品明细表行。"""
    badge_colors = {
        "设备": ("#3B82F615", "#3B82F6"),
        "硬件": ("#10B98115", "#10B981"),
        "软件": ("#8B5CF615", "#8B5CF6"),
        "服务": ("#F59E0B15", "#F59E0B"),
        "备件": ("#EF444415", "#EF4444"),
    }
    rows = []
    for p in products:
        bg, fg = badge_colors.get(p.get("category", ""), ("#3B82F615", "#3B82F6"))
        rows.append(
            f'<tr>\n'
            f'<td class="center">{p.get("seq","")}</td>\n'
            f'<td><span class="badge" style="background:{bg};color:{fg}">{p.get("category","")}</span></td>\n'
            f'<td class="name">{p.get("name","")}<br><small>{p.get("model","")}</small></td>\n'
            f'<td class="center">{p.get("qty","")}</td>\n'
            f'<td class="center">{p.get("unit","")}</td>\n'
            f'<td class="num">¥{p.get("unit_price",0):,}</td>\n'
            f'<td class="center discount">{p.get("discount_desc","—")}</td>\n'
            f'<td class="num strong">¥{p.get("subtotal",0):,}</td>\n'
            f'</tr>'
        )
    return "\n".join(rows)


def _build_category_cards(products: list, discounted_total: float) -> str:
    """生成五大类费用卡片。"""
    cat_totals = {}
    for p in products:
        cat = p.get("category", "其他")
        cat_totals[cat] = cat_totals.get(cat, 0) + p.get("subtotal", 0)

    icon_map = {"设备": "🔧", "硬件": "📡", "软件": "☁️", "服务": "🛠️", "备件": "📦"}
    cards = []
    for cat in ["设备", "硬件", "软件", "服务", "备件"]:
        total = cat_totals.get(cat, 0)
        pct = round(total / discounted_total * 100, 1) if discounted_total > 0 else 0
        icon = icon_map.get(cat, "📋")
        cards.append(
            f'<div class="cat-card">\n'
            f'<div class="cat-icon">{icon}</div>\n'
            f'<div class="cat-name">{cat}类</div>\n'
            f'<div class="cat-amount">¥{total:,}</div>\n'
            f'<div class="cat-pct">{pct}%</div>\n'
            f'</div>'
        )
    return "\n".join(cards)


def _build_grand_breakdown(products: list) -> str:
    """生成总价右侧分类明细。"""
    cat_totals = {}
    for p in products:
        cat = p.get("category", "其他")
        cat_totals[cat] = cat_totals.get(cat, 0) + p.get("subtotal", 0)
    items = []
    for cat in ["设备", "硬件", "软件", "服务", "备件"]:
        total = cat_totals.get(cat, 0)
        items.append(
            f'<div class="g-item"><span>{cat}类</span><span>¥{total:,}</span></div>'
        )
    return "\n".join(items)


def _build_alerts(data: dict) -> str:
    """生成需确认事项的 alert 块。"""
    alerts = data.get("alerts", [])
    if not alerts:
        return ""
    parts = []
    for text, a_type in alerts:
        css_class = "alert-warn" if a_type == "warn" else "alert-info"
        icon = "⚠️" if a_type == "warn" else "📋"
        parts.append(
            f'<div class="alert {css_class}">\n'
            f'<span class="alert-icon">{icon}</span>\n'
            f'<span>{text}</span>\n'
            f'</div>'
        )
    return "\n".join(parts)


def generate_html(data: dict, output_path: str) -> str:
    """从 full_data 字典 + HTML 模板生成报价单。"""
    template = _load_template()
    products = data.get("products", [])

    # 计算汇总
    cat_totals = {}
    for p in products:
        cat_totals[p.get("category", "其他")] = \
            cat_totals.get(p.get("category", "其他"), 0) + p.get("subtotal", 0)

    shipping_fee = data.get("shipping_fee", 0)
    shipping_desc = "¥0（同城免运费）" if shipping_fee == 0 else f"¥{shipping_fee:,}"

    # 模板替换
    replacements = {
        "{{title}}": f'{data.get("company_name","")} · 项目报价方案 — {data.get("client_name","")}',
        "{{header_title}}": data.get("header_title", f'{data.get("company_name","")} · 项目报价方案'),
        "{{header_subtitle}}": data.get("header_subtitle", f'为 {data.get("client_name","")} 提供专业服务'),
        "{{company_name}}": data.get("company_name", ""),
        "{{client_name}}": data.get("client_name", ""),
        "{{quote_no}}": data.get("quote_no", ""),
        "{{quote_date}}": data.get("quote_date", ""),
        "{{quoter_name}}": data.get("quoter_name", ""),
        "{{valid_until}}": data.get("valid_until", ""),
        "{{quoter_phone}}": data.get("quoter_phone", ""),
        "{{quoter_email}}": data.get("quoter_email", ""),
        "{{requirement_summary}}": data.get("requirement_summary", ""),
        "{{solution_overview}}": data.get("solution_overview", ""),
        "{{product_rows}}": _build_product_rows(products),
        "{{category_cards}}": _build_category_cards(products, data.get("discounted_total", 0)),
        "{{discounted_total_fmt}}": f'{data.get("discounted_total", 0):,}',
        "{{tax_amount_fmt}}": f'{data.get("tax_amount", 0):,.0f}',
        "{{shipping_fee_desc}}": shipping_desc,
        "{{grand_total_fmt}}": f'{data.get("grand_total", 0):,.0f}',
        "{{grand_total_cn}}": data.get("grand_total_cn", ""),
        "{{grand_breakdown}}": _build_grand_breakdown(products),
        "{{delivery_date}}": data.get("delivery_date", ""),
        "{{payment_terms}}": data.get("payment_terms", ""),
        "{{warranty}}": data.get("warranty", ""),
        "{{service_scope}}": data.get("service_scope", ""),
        "{{delivery_boundary}}": data.get("delivery_boundary", ""),
        "{{remarks}}": data.get("remarks", "无"),
    }

    html = template
    for key, val in replacements.items():
        html = html.replace(key, str(val))

    os.makedirs(os.path.dirname(output_path) or ".", exist_ok=True)
    with open(output_path, "w", encoding="utf-8") as f:
        f.write(html)

    return html


# ── QA Report Generator ──

def _load_qa_template() -> str:
    with open(QA_TEMPLATE, "r", encoding="utf-8") as f:
        return f.read()


def _build_qa_detail_rows(data: dict) -> str:
    """生成质检清单行（按角色分组，带分隔行和序号）。"""
    qa_checks = data.get("qa_checks", [])
    if not qa_checks:
        return '<tr><td colspan="4" style="text-align:center;color:#9CA3AF">暂无质检数据</td></tr>'

    result_icons = {"pass": '<span class="pass">✅ 通过</span>',
                    "warn": '<span class="warn">⚠️ 建议</span>',
                    "pending": '<span class="pending">❓ 待确认</span>'}
    rows = []
    last_role = None
    seq = 0
    for item in qa_checks:
        role = item.get("role", "")
        # Role separator row
        if role != last_role:
            last_role = role
            rows.append(
                f'<tr class="role-separator">'
                f'<td colspan="4">👤 {role}</td></tr>'
            )
        seq += 1
        icon = result_icons.get(item.get("result", "pending"), result_icons["pending"])
        rows.append(
            f'<tr><td style="text-align:center;color:#6B7280">{seq}</td>'
            f'<td>{item.get("question","")}</td><td>{icon}</td>'
            f'<td style="color:#6B7280;font-size:12px">{item.get("note","")}</td></tr>'
        )
    return "\n".join(rows)


def _build_role_summary_rows(data: dict) -> str:
    """生成分角色统计卡片。"""
    qa_checks = data.get("qa_checks", [])
    if not qa_checks:
        return ""

    # Group by role
    role_stats = {}
    for item in qa_checks:
        role = item.get("role", "其他")
        if role not in role_stats:
            role_stats[role] = {"pass": 0, "warn": 0, "pending": 0, "total": 0}
        role_stats[role][item.get("result", "pending")] += 1
        role_stats[role]["total"] += 1

    cards = []
    for role, stats in role_stats.items():
        cards.append(
            f'<div class="role-card">'
            f'<div class="role-name">👤 {role}</div>'
            f'<div class="role-stats">'
            f'<span class="rs-pass">✅ {stats["pass"]}</span>'
            f'<span class="rs-warn">⚠️ {stats["warn"]}</span>'
            f'<span class="rs-pending">❓ {stats["pending"]}</span>'
            f'</div></div>'
        )
    return "\n".join(cards)


def _build_risk_alerts(data: dict) -> str:
    """生成风险提醒。"""
    risks = data.get("qa_risks", [])
    if not risks:
        return '<p style="color:#9CA3AF;font-size:13px">无特殊风险项</p>'
    parts = []
    for text, level in risks:
        css = {"danger": "alert-danger", "warn": "alert-warn", "info": "alert-info"}.get(level, "alert-info")
        icon = {"danger": "🚨", "warn": "⚠️", "info": "ℹ️"}.get(level, "ℹ️")
        parts.append(
            f'<div class="alert-box {css}"><span class="alert-icon">{icon}</span><span>{text}</span></div>'
        )
    return "\n".join(parts)


def _build_approval_items(data: dict) -> str:
    """生成审批清单。"""
    items = data.get("qa_approvals", [])
    if not items:
        return '<p style="color:#9CA3AF;font-size:13px">无待审批项</p>'
    rows = []
    for item in items:
        status = "⬜ 待审批" if item.get("status") != "done" else "✅ 已审批"
        rows.append(
            f'<div style="display:flex;justify-content:space-between;align-items:center;'
            f'padding:10px 14px;border-bottom:1px solid #E5E7EB;font-size:13px">'
            f'<span>{item.get("title","")}</span>'
            f'<span style="font-weight:500">{item.get("approver","")} · {status}</span>'
            f'</div>'
        )
    return "\n".join(rows)


def generate_qa_report(data: dict, output_path: str) -> str:
    """从 full_data 生成质检报告 HTML。"""
    template = _load_qa_template()

    qa_checks = data.get("qa_checks", [])
    pass_count = sum(1 for c in qa_checks if c.get("result") == "pass")
    warn_count = sum(1 for c in qa_checks if c.get("result") == "warn")
    pending_count = sum(1 for c in qa_checks if c.get("result") == "pending")

    budget = data.get("qa_budget", 0)
    grand_total = data.get("grand_total", 1)
    budget_ratio = min(round(grand_total / budget * 100, 1) if budget > 0 else 100, 200)
    budget_overflow = round((grand_total - budget) / budget * 100, 1) if budget > 0 else 0
    budget_warning = "，请关注议价策略" if budget_overflow > 0 else ""

    replacements = {
        "{{title}}": f'报价单质检报告 — {data.get("client_name","")}',
        "{{report_title}}": "报价单 · 内部质检报告",
        "{{report_subtitle}}": f'{data.get("quote_no","")} · 仅供内部审批使用',
        "{{company_name}}": data.get("company_name", ""),
        "{{client_name}}": data.get("client_name", ""),
        "{{quoter_name}}": data.get("quoter_name", ""),
        "{{quoter_phone}}": data.get("quoter_phone", ""),
        "{{quoter_email}}": data.get("quoter_email", ""),
        "{{quote_no}}": data.get("quote_no", ""),
        "{{quote_date}}": data.get("quote_date", ""),
        "{{valid_until}}": data.get("valid_until", ""),
        "{{grand_total_fmt}}": f'{grand_total:,.0f}',
        "{{overall_pass}}": str(pass_count),
        "{{overall_warn}}": str(warn_count),
        "{{overall_pending}}": str(pending_count),
        "{{overall_total}}": str(len(qa_checks)),
        "{{role_summary_rows}}": _build_role_summary_rows(data),
        "{{qa_detail_rows}}": _build_qa_detail_rows(data),
        "{{budget_amount_fmt}}": f'{budget:,}' if budget > 0 else "未设定",
        "{{budget_ratio}}": str(budget_ratio),
        "{{budget_overflow}}": str(budget_overflow),
        "{{budget_warning}}": budget_warning,
        "{{risk_alerts}}": _build_risk_alerts(data),
        "{{approval_items}}": _build_approval_items(data),
    }

    html = template
    for key, val in replacements.items():
        html = html.replace(key, str(val))

    os.makedirs(os.path.dirname(output_path) or ".", exist_ok=True)
    with open(output_path, "w", encoding="utf-8") as f:
        f.write(html)

    return html


# ── Excel Generator (委托 excel_builder) ──

def generate_excel(data: dict, output_path: str) -> str:
    """调用 excel_builder.py 生成 Excel 报价单。"""
    builder = os.path.join(SKILL_DIR, "scripts", "excel_builder.py")
    result = subprocess.run(
        [sys.executable, builder, "build", "--data", "-", "--output", output_path],
        input=json.dumps(data, ensure_ascii=False),
        capture_output=True, text=True
    )
    if result.returncode != 0:
        print(json.dumps({"error": result.stderr}, ensure_ascii=False), file=sys.stderr)
        sys.exit(1)
    return output_path


# ── PDF Generator ──

def generate_pdf(html_path: str, output_path: str) -> tuple:
    """尝试生成 PDF。返回 (success, message)。"""
    try:
        from weasyprint import HTML
        HTML(filename=html_path).write_pdf(output_path)
        return True, f"PDF generated with weasyprint: {output_path}"
    except ImportError:
        pass
    except Exception:
        pass

    wk = shutil.which("wkhtmltopdf")
    if wk:
        try:
            subprocess.run([wk, html_path, output_path],
                           check=True, capture_output=True)
            return True, f"PDF generated with wkhtmltopdf: {output_path}"
        except subprocess.CalledProcessError:
            pass

    return False, (
        "未检测到 PDF 生成工具。请安装 weasyprint（pip install weasyprint）"
        "或 wkhtmltopdf（https://wkhtmltopdf.org），"
        "或手动在浏览器中打开 HTML 后 Ctrl+P / Command+P 打印为 PDF。"
    )


# ── CLI ──

def cmd_html(args):
    with open(args.data, "r", encoding="utf-8") as f:
        data = json.load(f)
    generate_html(data, args.output)
    print(json.dumps({"ok": True, "output": args.output}, ensure_ascii=False))


def cmd_excel(args):
    with open(args.data, "r", encoding="utf-8") as f:
        data = json.load(f)
    generate_excel(data, args.output)
    print(json.dumps({"ok": True, "output": args.output}, ensure_ascii=False))


def cmd_qa(args):
    with open(args.data, "r", encoding="utf-8") as f:
        data = json.load(f)
    generate_qa_report(data, args.output)
    print(json.dumps({"ok": True, "output": args.output}, ensure_ascii=False))


def cmd_pdf(args):
    success, msg = generate_pdf(args.html, args.output)
    print(json.dumps(
        {"ok": success, "message": msg, "output": args.output if success else None},
        ensure_ascii=False
    ))


def cmd_all(args):
    out_dir = args.out_dir
    prefix = args.name_prefix or "报价方案"
    os.makedirs(out_dir, exist_ok=True)

    with open(args.data, "r", encoding="utf-8") as f:
        data = json.load(f)

    results = {}

    # HTML (客户端，无质检)
    html_path = os.path.join(out_dir, f"{prefix}.html")
    generate_html(data, html_path)
    results["html"] = html_path

    # Excel (客户端，无质检)
    excel_path = os.path.join(out_dir, "报价单.xlsx")
    generate_excel(data, excel_path)
    results["excel"] = excel_path

    # QA Report (内部审批)
    qa_path = os.path.join(out_dir, "报价单质检报告.html")
    generate_qa_report(data, qa_path)
    results["qa_report"] = qa_path

    # PDF (try)
    pdf_path = os.path.join(out_dir, f"{prefix}.pdf")
    success, msg = generate_pdf(html_path, pdf_path)
    results["pdf"] = {"path": pdf_path if success else None,
                      "success": success, "message": msg}

    print(json.dumps(results, ensure_ascii=False, indent=2))


def main():
    parser = argparse.ArgumentParser(description="wx-quote-assistant Generators")
    sub = parser.add_subparsers(dest="command", required=True)

    p_html = sub.add_parser("html", help="Generate HTML quote")
    p_html.add_argument("--data", required=True, help="Path to full_data.json")
    p_html.add_argument("--output", required=True, help="Output HTML path")
    p_html.set_defaults(func=cmd_html)

    p_excel = sub.add_parser("excel", help="Generate Excel quote")
    p_excel.add_argument("--data", required=True, help="Path to full_data.json")
    p_excel.add_argument("--output", required=True, help="Output .xlsx path")
    p_excel.set_defaults(func=cmd_excel)

    p_qa = sub.add_parser("qa", help="Generate QA report")
    p_qa.add_argument("--data", required=True, help="Path to full_data.json")
    p_qa.add_argument("--output", required=True, help="Output HTML path")
    p_qa.set_defaults(func=cmd_qa)

    p_pdf = sub.add_parser("pdf", help="Generate PDF from HTML")
    p_pdf.add_argument("--html", required=True)
    p_pdf.add_argument("--output", required=True)
    p_pdf.set_defaults(func=cmd_pdf)

    p_all = sub.add_parser("all", help="Generate all formats")
    p_all.add_argument("--data", required=True, help="Path to full_data.json")
    p_all.add_argument("--out-dir", required=True)
    p_all.add_argument("--name-prefix", default="报价方案")
    p_all.set_defaults(func=cmd_all)

    args = parser.parse_args()
    args.func(args)


if __name__ == "__main__":
    main()
