#!/usr/bin/env python3
"""
script-post-check — 剧本英文台词后处理复核
纯代码规则链，逐项检查 F 列英文台词。

Usage:
    python3 check.py --url "https://makee-interactive.feishu.cn/wiki/xxx"
    python3 check.py --url "https://..." --rule 长句拆分
    python3 check.py --url "https://..." --rule 标点检查
    python3 check.py --list
"""

import argparse
import json
import re
import sys
import os

# ── Feishu API helpers ──────────────────────────────────────────────

def get_bot_token():
    cred_path = os.path.expanduser("/root/.openclaw/credentials/xiaoyan/config.json")
    with open(cred_path) as f:
        cfg = json.load(f)
    app_id = "cli_a931175d41799cc7"
    app_secret = cfg["apps"][0]["appSecret"]
    import requests
    r = requests.post("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
                      json={"app_id": app_id, "app_secret": app_secret})
    return r.json()["tenant_access_token"]


def get_node_info(wiki_token):
    """Get node info from wiki token."""
    import subprocess
    result = subprocess.run(
        ["lark-cli", "wiki", "spaces", "get_node",
         "--params", json.dumps({"token": wiki_token}), "--as", "bot"],
        capture_output=True, text=True,
        env={**os.environ, "LARKSUITE_CLI_CONFIG_DIR": "/root/.openclaw/credentials/xiaoyan"}
    )
    data = json.loads(result.stdout)
    if data.get("code") != 0:
        print(f"ERROR: {data.get('msg')}")
        sys.exit(1)
    node = data["data"]["node"]
    return {
        "space_id": node["space_id"],
        "obj_token": node["obj_token"],
        "obj_type": node["obj_type"],
        "title": node.get("title", ""),
        "has_child": node.get("has_child", False),
    }


def fetch_doc_markdown(obj_token):
    """Fetch document content as markdown."""
    import subprocess
    result = subprocess.run(
        ["lark-cli", "docs", "+fetch", "--doc", obj_token, "--as", "bot"],
        capture_output=True, text=True,
        env={**os.environ, "LARKSUITE_CLI_CONFIG_DIR": "/root/.openclaw/credentials/xiaoyan"}
    )
    data = json.loads(result.stdout)
    if not data.get("ok"):
        print(f"ERROR: {data.get('message')}")
        sys.exit(1)
    return data["data"]["markdown"], data["data"]["title"]


def extract_sheet_token(markdown):
    """Extract spreadsheet_token and sheet_id from markdown."""
    # Find <sheet token="xxx"/> pattern
    m = re.search(r'<sheet\s+token="([^"]+)"', markdown)
    if not m:
        print("ERROR: No embedded sheet found in document")
        sys.exit(1)
    full_token = m.group(1)
    parts = full_token.split("_", 1)
    if len(parts) != 2:
        print(f"ERROR: Cannot parse sheet token: {full_token}")
        sys.exit(1)
    return parts[0], parts[1]


def read_column(token, spreadsheet_token, sheet_id, col_letter="F"):
    """Read a column from the sheet, return {row_num: value}."""
    import requests
    # First get sheet metadata to know row count
    r = requests.get(
        f"https://open.feishu.cn/open-apis/sheets/v3/spreadsheets/{spreadsheet_token}/sheets/query",
        headers={"Authorization": f"Bearer {token}"}
    )
    sheets_data = r.json()
    row_count = 0
    for s in sheets_data.get("data", {}).get("sheets", []):
        if s["sheet_id"] == sheet_id:
            row_count = s.get("grid_properties", {}).get("row_count", 250)
            break

    if row_count == 0:
        row_count = 250

    r = requests.get(
        f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{spreadsheet_token}/values/{sheet_id}!{col_letter}1:{col_letter}{row_count}?valueRenderOption=ToString",
        headers={"Authorization": f"Bearer {token}"}
    )
    values = r.json().get("data", {}).get("valueRange", {}).get("values", [])
    result = {}
    for i, row in enumerate(values):
        row_num = i + 1
        val = row[0] if row else None
        if val and val.strip():
            result[row_num] = val.strip()
    return result


def write_cell(token, spreadsheet_token, sheet_id, row, col_letter, value):
    """Write a single cell."""
    import requests
    r = requests.put(
        f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{spreadsheet_token}/values",
        headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
        json={
            "valueRange": {
                "range": f"{sheet_id}!{col_letter}{row}:{col_letter}{row}",
                "values": [[value]]
            }
        }
    )
    return r.json()


def insert_row(token, spreadsheet_token, sheet_id, after_row):
    """Insert a blank row after the given row (1-based)."""
    import requests
    r = requests.post(
        f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{spreadsheet_token}/insert_dimension_range",
        headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
        json={
            "dimension": {
                "sheetId": sheet_id,
                "majorDimension": "ROWS",
                "startIndex": after_row,  # 0-based, insert after this row
                "endIndex": after_row + 1
            },
            "inheritStyle": "BEFORE"
        }
    )
    return r.json()


# ── Rule implementations ────────────────────────────────────────────

def split_sentences(text):
    """Split text into sentences."""
    placeholder = "<<<ELLIPSIS>>>"
    text_clean = text.replace("...", placeholder)
    parts = re.split(r'(?<=[.!?])\s+', text_clean)
    parts = [p.replace(placeholder, "...").strip() for p in parts if p.strip()]
    return parts


def count_words(text):
    return len(text.split())


def rule_long_sentence_split(token, spreadsheet_token, sheet_id, f_col):
    """
    Rule 1: 长句拆分
    Definition: >1 sentence AND total words >= 7
    Split: keep first N sentences with cumulative words >= 7, rest to new rows
    """
    print("\n" + "=" * 60)
    print("📏 规则1：长句拆分")
    print("=" * 60)

    # Identify long lines
    long_lines = []
    for row_num in sorted(f_col.keys()):
        text = f_col[row_num]
        sentences = split_sentences(text)
        total_words = count_words(text)
        num_sentences = len(sentences)

        if num_sentences > 1 and total_words >= 7:
            cumulative = 0
            split_idx = 0
            for i, s in enumerate(sentences):
                cumulative += count_words(s)
                split_idx = i + 1
                if cumulative >= 7:
                    break

            keep = " ".join(sentences[:split_idx])
            rest = sentences[split_idx:]

            if rest:
                long_lines.append({
                    'row': row_num,
                    'text': text,
                    'keep': keep,
                    'rest': rest,
                })

    if not long_lines:
        print("  ✅ 无需拆分")
        return []

    # Process from bottom to top to avoid row offset
    long_lines.sort(key=lambda x: x['row'], reverse=True)
    results = []

    for item in long_lines:
        row = item['row']
        keep = item['keep']
        rest_text = " ".join(item['rest'])

        print(f"\n  第{row}行：{item['text']}")
        print(f"    → 保留：{keep}")

        # Insert row
        resp = insert_row(token, spreadsheet_token, sheet_id, row)
        if resp.get("code") != 0:
            print(f"    ❌ 插入行失败：{resp}")
            continue

        # Write keep to original row
        resp = write_cell(token, spreadsheet_token, sheet_id, row, "F", keep)
        if resp.get("code") != 0:
            print(f"    ❌ 写入保留文本失败：{resp}")
            continue

        # Write rest to new row
        resp = write_cell(token, spreadsheet_token, sheet_id, row + 1, "F", rest_text)
        if resp.get("code") != 0:
            print(f"    ❌ 写入拆分文本失败：{resp}")
            continue

        print(f"    → 拆分：{rest_text}")
        print(f"    ✅ 完成")
        results.append({
            'row': row,
            'original': item['text'],
            'keep': keep,
            'split': rest_text,
        })

    print(f"\n  📊 长句拆分：发现 {len(long_lines)} 处，修正 {len(results)} 处")
    return results


def rule_punctuation_check(token, spreadsheet_token, sheet_id, f_col):
    """
    Rule 2: 标点检查
    - ?! 连用 → 根据句义保留一个
    - 全角标点 → 替换为半角
    - 多余感叹号 → 归一为单个
    - Markdown 残留 → 清除
    """
    print("\n" + "=" * 60)
    print("🔤 规则2：标点检查")
    print("=" * 60)

    results = []
    fixes = []

    for row_num in sorted(f_col.keys()):
        text = f_col[row_num]
        original = text
        changes = []

        # 1. Check ?! combo
        if "?!" in text:
            text = text.replace("?!", "!")
            changes.append(f"?!→!")

        if "!?" in text:
            text = text.replace("!?", "!")
            changes.append(f"!?→!")

        # 2. Full-width punctuation → half-width
        replacements = {
            "！": "!",
            "？": "?",
            "，": ",",
            "。": ".",
        }
        for full, half in replacements.items():
            if full in text:
                count = text.count(full)
                text = text.replace(full, half)
                changes.append(f"{full}→{half}（{count}处）")

        # 3. Multiple exclamation marks → single
        multi_bang = re.findall(r'!{2,}', text)
        if multi_bang:
            text = re.sub(r'!{2,}', '!', text)
            changes.append(f"!!→!（{len(multi_bang)}处）")

        # 4. Markdown residue
        md_patterns = [r'\*\*', r'__', r'\*([^*])', r'_([^_])']
        for pat in md_patterns:
            if re.search(pat, text):
                text = re.sub(pat, r'\1', text)
                changes.append(f"Markdown残留→清除")

        if text != original:
            resp = write_cell(token, spreadsheet_token, sheet_id, row_num, "F", text)
            if resp.get("code") != 0:
                print(f"  ❌ 第{row_num}行写入失败：{resp}")
                continue

            print(f"  第{row_num}行：{original}")
            print(f"    → {text}")
            print(f"    修正：{', '.join(changes)}")
            fixes.append({
                'row': row_num,
                'original': original,
                'fixed': text,
                'changes': changes,
            })

    if not fixes:
        print("  ✅ 无需修正")
    else:
        print(f"\n  📊 标点检查：发现 {len(fixes)} 处问题，全部修正")

    return fixes


# ── Main ─────────────────────────────────────────────────────────────

def parse_url(url):
    """Extract wiki_token from feishu URL."""
    m = re.search(r'/wiki/([A-Za-z0-9]+)', url)
    if not m:
        print("ERROR: Cannot parse wiki token from URL")
        sys.exit(1)
    return m.group(1)


def list_rules():
    print("可用规则：")
    print("  长句拆分  — >1句且≥7词的长句自动拆分")
    print("  标点检查  — ?!连用/全角标点/多余感叹号/Markdown残留")


def main():
    parser = argparse.ArgumentParser(description="剧本英文台词后处理复核")
    parser.add_argument("--url", help="飞书文档链接")
    parser.add_argument("--rule", help="指定规则（长句拆分/标点检查），不指定则执行全部")
    parser.add_argument("--list", action="store_true", help="列出可用规则")
    args = parser.parse_args()

    if args.list:
        list_rules()
        return

    if not args.url:
        print("ERROR: 请提供飞书文档链接（--url）")
        sys.exit(1)

    # Parse URL
    wiki_token = parse_url(args.url)
    print(f"📋 解析文档：{wiki_token}")

    # Get node info
    node = get_node_info(wiki_token)
    print(f"📄 文档：{node['title']}")
    print(f"   obj_token: {node['obj_token']}")

    # Fetch document
    markdown, title = fetch_doc_markdown(node['obj_token'])

    # Extract sheet
    spreadsheet_token, sheet_id = extract_sheet_token(markdown)
    print(f"📊 Sheet: {spreadsheet_token} / {sheet_id}")

    # Get bot token
    bot_token = get_bot_token()

    # Read F column
    f_col = read_column(bot_token, spreadsheet_token, sheet_id, "F")
    print(f"📖 F列共 {len(f_col)} 行有内容")

    # Execute rules
    all_results = {"长句拆分": [], "标点检查": []}

    if args.rule:
        if args.rule == "长句拆分":
            all_results["长句拆分"] = rule_long_sentence_split(bot_token, spreadsheet_token, sheet_id, f_col)
        elif args.rule == "标点检查":
            all_results["标点检查"] = rule_punctuation_check(bot_token, spreadsheet_token, sheet_id, f_col)
        else:
            print(f"ERROR: 未知规则 '{args.rule}'，可用：长句拆分、标点检查")
            sys.exit(1)
    else:
        # Run all rules — read fresh F column for each rule since previous rules may have changed it
        f_col_1 = read_column(bot_token, spreadsheet_token, sheet_id, "F")
        all_results["长句拆分"] = rule_long_sentence_split(bot_token, spreadsheet_token, sheet_id, f_col_1)

        f_col_2 = read_column(bot_token, spreadsheet_token, sheet_id, "F")
        all_results["标点检查"] = rule_punctuation_check(bot_token, spreadsheet_token, sheet_id, f_col_2)

    # Summary
    print("\n" + "=" * 60)
    print(f"📋 剧本复核报告 — {title}")
    print("=" * 60)

    total_checked = len(f_col)
    total_found = sum(len(v) for v in all_results.values())
    total_fixed = total_found

    print(f"\n| 规则 | 检查行数 | 发现问题 | 已修正 |")
    print(f"|------|---------|---------|--------|")
    for rule_name, fixes in all_results.items():
        if args.rule and rule_name != args.rule:
            continue
        found = len(fixes)
        status = "✅" if found == 0 else f"{found} ✅"
        print(f"| {rule_name} | {total_checked} | {found} | {status} |")

    print(f"\n✅ 复核完成。")


if __name__ == "__main__":
    main()
