#!/usr/bin/env python3
"""wx-quote-assistant — 模板解析引擎

解析含 {{variable}} 占位符的模板，支持单值替换、循环块、条件块。

CLI 用法:
  python3 template_parser.py list-vars --template <path>
  python3 template_parser.py parse --template <path> --data <json_path> [--output <path>]
"""

import argparse
import json
import os
import re
import sys


# 占位符正则: {{变量名}}
VAR_PATTERN = re.compile(r"\{\{(\w+)\}\}")

# 循环块: {{#array_key}} ... {{/array_key}}
LOOP_PATTERN = re.compile(r"\{\{#(\w+)\}\}(.*?)\{\{/(\1)\}\}", re.DOTALL)

# 条件块: {{#if var}} ... {{/if}}
IF_PATTERN = re.compile(r"\{\{#if\s+(\w+)\}\}(.*?)\{\{/if\}\}", re.DOTALL)


def list_variables(template_text: str) -> list[str]:
    """提取模板中所有唯一的变量名。"""
    vars_set = set()

    # 单值变量
    for m in VAR_PATTERN.finditer(template_text):
        var_name = m.group(1)
        # 跳过循环块标记和条件块标记（#开头的）
        if not var_name.startswith("#") and var_name != "if" and var_name != "/if":
            vars_set.add(var_name)

    # 循环块变量
    for m in LOOP_PATTERN.finditer(template_text):
        # m.group(1) 是数组名, m.group(2) 是内部模板
        inner = m.group(2)
        for vm in VAR_PATTERN.finditer(inner):
            vars_set.add(f"{m.group(1)}[].{vm.group(1)}")

    # 条件块变量
    for m in IF_PATTERN.finditer(template_text):
        vars_set.add(m.group(1))

    return sorted(vars_set)


def _resolve_value(data: dict, var_path: str):
    """解析点分隔的变量路径，如 products[].name 或 company_name。"""
    # 处理循环变量: array_name[].field → 返回模板占位符，在实际渲染时替换
    if "[]." in var_path:
        return f"{{{var_path}}}"  # 保留给循环渲染处理

    # 直接取值
    keys = var_path.split(".")
    current = data
    for k in keys:
        if isinstance(current, dict) and k in current:
            current = current[k]
        else:
            return f"{{{{{var_path}}}}}"
    return current


def parse_template(template_text: str, data: dict) -> str:
    """将数据填充到模板中，返回渲染后的文本。"""
    result = template_text

    # 1. 处理循环块
    def expand_loop(match):
        array_key = match.group(1)
        inner_template = match.group(2)
        items = data.get(array_key, [])

        if not items:
            return f"<!-- {array_key}: 无数据 -->"

        rows = []
        for item in items:
            row = inner_template
            # 替换循环内的变量
            for vm in VAR_PATTERN.finditer(inner_template):
                var_name = vm.group(1)
                if var_name in item:
                    row = row.replace(f"{{{{{var_name}}}}}", str(item[var_name]))
            rows.append(row)
        return "".join(rows)

    result = LOOP_PATTERN.sub(expand_loop, result)

    # 2. 处理条件块
    def expand_if(match):
        var_name = match.group(1)
        inner = match.group(2)
        val = data.get(var_name, None)
        if val and val not in (0, 0.0, False, "", None):
            return inner
        return ""

    result = IF_PATTERN.sub(expand_if, result)

    # 3. 替换剩余单值变量
    def replace_var(match):
        var_name = match.group(1)
        if var_name in data and not isinstance(data[var_name], (list, dict)):
            return str(data[var_name])
        return f"{{{{{var_name}}}}}"  # 保留未匹配的

    result = VAR_PATTERN.sub(replace_var, result)

    return result


def cmd_list_vars(args) -> None:
    """列出模板中的所有变量。"""
    with open(args.template, "r", encoding="utf-8") as f:
        text = f.read()

    variables = list_variables(text)
    print(json.dumps({"template": args.template, "variables": variables}, ensure_ascii=False, indent=2))


def cmd_parse(args) -> None:
    """解析模板并替换变量。"""
    with open(args.template, "r", encoding="utf-8") as f:
        text = f.read()

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

    rendered = parse_template(text, data)

    if args.output:
        os.makedirs(os.path.dirname(args.output) or ".", exist_ok=True)
        with open(args.output, "w", encoding="utf-8") as f:
            f.write(rendered)
        print(json.dumps({"ok": True, "output": args.output}, ensure_ascii=False))
    else:
        print(rendered)


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

    p_list = sub.add_parser("list-vars", help="List all variables in a template")
    p_list.add_argument("--template", required=True)
    p_list.set_defaults(func=cmd_list_vars)

    p_parse = sub.add_parser("parse", help="Parse template with data")
    p_parse.add_argument("--template", required=True)
    p_parse.add_argument("--data", required=True)
    p_parse.add_argument("--output", default=None)
    p_parse.set_defaults(func=cmd_parse)

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


if __name__ == "__main__":
    main()
