#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""am 桥接器 —— 把生产报告 markdown 转成 answer-me-with-html 草稿并渲染

用途（2026-10-19 用户要求：所有 HTML 一律走 am）：
  md (复盘/早盘/LXXG/研究报告) → am draft (frontmatter + ## panel) → am render → qpyjs.com

设计要点：
1. 只做格式转换，不改内容（内容由上游生成器/fill 决定）
2. `## xxx` 原样作 panel；`### / ####` 保留为面板内小标题
3. 状态行 blockquote（`> 行情:...`）→ frontmatter 之外的 intro 或 kv
4. 表格原样保留（am 支持 GFM 表格）
5. STE 检查默认关闭（财经长句无法压到 45 字，且会阻断渲染）

用法：
  python3 am_bridge.py <input.md> <output.html> [--title T] [--subtitle S]
                       [--template doc|sheet] [--theme paper|shadcn|blueprint]
                       [--source S] [--cols N] [--strict]
"""
import argparse
import pathlib
import re
import subprocess
import sys

AM = "/root/.hermes/skills/answer-me-with-html/scripts/am.mjs"
NODE = "node"


def split_frontmatter(text):
    """剥离已有 YAML frontmatter, 返回 (meta_dict, body)。"""
    meta = {}
    if text.startswith("---\n"):
        end = text.find("\n---\n", 4)
        if end > 0:
            fm = text[4:end]
            for line in fm.split("\n"):
                m = re.match(r"^(\w[\w-]*):\s*(.*)$", line)
                if m:
                    meta[m.group(1)] = m.group(2).strip().strip('"\'')
            text = text[end + 5:]
    return meta, text


def extract_status_block(body):
    """提取开头的 blockquote 状态行（复盘 KPI），返回 (status_lines, rest)。"""
    lines = body.split("\n")
    out, i = [], 0
    # 跳过空行
    while i < len(lines) and not lines[i].strip():
        i += 1
    while i < len(lines) and lines[i].lstrip().startswith(">"):
        out.append(re.sub(r"^\s*>\s?", "", lines[i]))
        i += 1
    rest = "\n".join(lines[i:])
    return out, rest


def status_to_kv(status_lines):
    """把 `> 行情:春 | 综合评分:72分 | ...` 转成 am kv 块。"""
    if not status_lines:
        return ""
    txt = " ".join(status_lines)
    # 去掉 markdown 强调
    txt = re.sub(r"\*\*(.+?)\*\*", r"\1", txt)
    pairs = [p.strip() for p in re.split(r"[|｜]", txt) if p.strip()]
    rows = []
    for p in pairs:
        m = re.match(r"^([^:：]{1,20})[:：]\s*(.+)$", p)
        if m:
            rows.append(f"{m.group(1).strip()}: {m.group(2).strip()}")
    if not rows:
        return ""
    return "```kv\n" + "\n".join(rows) + "\n```\n"


def apply_components(body):
    """把密集段落转成 am 原生组件 (callout/limits/kv)。2026-10-19 用户要求。"""
    try:
        import am_components
        return am_components.transform_sections(body)
    except Exception as e:
        print(f"[am_bridge] components skipped: {e}", file=sys.stderr)
        return body


def clean_body(body):
    """清理不适合 am 的痕迹：
    - 分隔线 `---` 在 body 中会被误认为 frontmatter 边界 → 转成空行
    - 纯 emoji 标题前缀保留（am 支持）
    """
    body = re.sub(r"^\s*---\s*$", "", body, flags=re.M)
    # 折叠 3+ 连续空行
    body = re.sub(r"\n{3,}", "\n\n", body)
    return body.strip()


def md_to_am_draft(md_text, title=None, subtitle=None, template="doc",
                   theme="shadcn", source=None, cols=None):
    """生产 md → am 草稿文本。"""
    meta, body = split_frontmatter(md_text)
    title = title or meta.get("title") or "报告"
    subtitle = subtitle or meta.get("subtitle") or ""
    source = source or meta.get("source") or ""

    status, body = extract_status_block(body)
    kv_block = status_to_kv(status)
    body = clean_body(body)
    body = apply_components(body)

    # 若无 `## ` 面板但有 `# ` 标题，把 `#` 转 `##`
    if "\n## " not in "\n" + body and "\n# " in "\n" + body:
        body = re.sub(r"^#\s+", "## ", body, flags=re.M)

    head = ["---", f"template: {template}", f"theme: {theme}",
            f"title: {title}"]
    if subtitle:
        head.append(f"subtitle: {subtitle}")
    if cols:
        head.append(f"cols: {cols}")
    if source:
        head.append(f"source: {source}")
    head.append("---")

    parts = ["\n".join(head), ""]
    if kv_block:
        parts.append(kv_block)
    parts.append(body)
    return "\n".join(parts)


def render(draft_text, out_path, style="off", draft_path=None):
    """调 am render。返回 (ok, stdout, stderr)。"""
    dpath = draft_path or str(pathlib.Path(out_path).with_suffix(".am.md"))
    pathlib.Path(dpath).write_text(draft_text, encoding="utf-8")
    cmd = [NODE, AM, "render", "--no-open", "--style", style,
           "-o", out_path, dpath]
    p = subprocess.run(cmd, capture_output=True, text=True, timeout=180)
    return p.returncode == 0, p.stdout, p.stderr


def convert(md_path, out_path, **kw):
    """一步到位：md 文件 → am 草稿 → 渲染 HTML。"""
    md_text = pathlib.Path(md_path).read_text(encoding="utf-8")
    style = "strict" if kw.pop("strict", False) else "off"
    draft = md_to_am_draft(md_text, **kw)
    return render(draft, out_path, style=style)


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("md")
    ap.add_argument("out")
    ap.add_argument("--title")
    ap.add_argument("--subtitle")
    ap.add_argument("--template", default="doc", choices=["doc", "sheet"])
    ap.add_argument("--theme", default="shadcn",
                    choices=["paper", "shadcn", "blueprint", "auto"])
    ap.add_argument("--source")
    ap.add_argument("--cols", type=int)
    ap.add_argument("--strict", action="store_true")
    ap.add_argument("--draft-only", action="store_true",
                    help="只生成 am 草稿, 不渲染")
    a = ap.parse_args()

    md_text = pathlib.Path(a.md).read_text(encoding="utf-8")
    draft = md_to_am_draft(md_text, title=a.title, subtitle=a.subtitle,
                           template=a.template, theme=a.theme,
                           source=a.source, cols=a.cols)
    if a.draft_only:
        dpath = str(pathlib.Path(a.out).with_suffix(".am.md"))
        pathlib.Path(dpath).write_text(draft, encoding="utf-8")
        print(f"draft: {dpath}")
        return 0
    ok, out, err = render(draft, a.out,
                          style="strict" if a.strict else "off")
    print(out.strip() or err.strip())
    return 0 if ok else 1


if __name__ == "__main__":
    sys.exit(main())
