"""
Unit Challenge 听力审校脚本：P1/P2/P4/P7（P5/P6无数据，P3跳过）
"""
import json, subprocess, sys, os

APP_TOKEN = "CMHSbUUjka3TrUsaxxEc297ongf"
SKILL_SCRIPT = "/root/.openclaw/workspace-xiaoyan/business_production/_shared/lark_bitable_operate_as_bot/scripts/operate_bitable.sh"
CRED_FILE = "/root/.openclaw/credentials/xiaoyan/config.json"

# Standard ability tags (from ability_tags.md)
ALL_TAGS = {
    # L1
    "显性信息定位｜关键词识别", "基础语境理解｜场景/行为理解", "图文判断｜句图一致性",
    "扫读定位｜信息匹配", "主旨理解｜段落/文本大意", "释义选词｜定义匹配",
    "对话理解｜问答匹配", "标识与通知理解｜Signs & Notices",
    # L2
    "细节理解｜事实信息提取", "词义理解｜语境义判断", "同义替换｜词/短语级",
    "语法结构识别｜完形填空", "推理判断｜原因/结果",
}

TAG_MAP = {
    "信息提取": "细节理解｜事实信息提取",
    "信息定位": "扫读定位｜信息匹配",
    "信息定位与提取": "扫读定位｜信息匹配",
    "细节理解": "细节理解｜事实信息提取",
    "因果推断": "推理判断｜原因/结果",
    "推理判断": "推理判断｜原因/结果",
    "主旨归纳": "主旨理解｜段落/文本大意",
    "主旨概括": "主旨理解｜段落/文本大意",
    "信息匹配": "扫读定位｜信息匹配",
    "同义替换": "同义替换｜词/短语级",
    "词义理解": "词义理解｜语境义判断",
    "语法结构": "语法结构识别｜完形填空",
}

# Per-type required question fields
TYPE_FIELDS = {
    "listening_choicePic": ["question", "questionAudio", "optionsImage", "answer", "ability", "explanation"],
    "listening_choiceShort": ["question", "questionAudio", "options", "answer", "ability", "explanation"],
    "listening_tableCloze": ["options", "answer", "ability", "explanation"],  # no question field
    "listening_drag": ["imageInfo", "optionList", "answer", "ability", "explanation"],
    "listening_matchInfo": ["question", "options", "answer", "ability", "explanation"],
    "listening_choosePic": ["question", "questionAudio", "optionsImage", "answer", "ability", "explanation"],
}

def get_bot_token():
    with open(CRED_FILE) as f:
        cfg = json.load(f)
    app_id = cfg['apps'][0]['appId']
    app_secret = cfg['apps'][0]['appSecret']
    import urllib.request
    req = urllib.request.Request(
        "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
        data=json.dumps({"app_id": app_id, "app_secret": app_secret}).encode(),
        headers={"Content-Type": "application/json"}
    )
    resp = urllib.request.urlopen(req)
    return json.loads(resp.read())['tenant_access_token']

def backfill_by_curl(record_id, table_id, audit_text):
    """Use direct curl to backfill audit result"""
    token = get_bot_token()
    import urllib.request
    
    body = json.dumps({"fields": {"审校结果": audit_text}})
    url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{table_id}/records/{record_id}"
    
    req = urllib.request.Request(url, data=body.encode(), method="PUT", headers={
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json"
    })
    resp = urllib.request.urlopen(req)
    result = json.loads(resp.read())
    return result.get('code') == 0, result

def audit_question(q, req_fields, ftype):
    """Audit a single question"""
    errors = []
    warnings = []
    tag_issues = []
    
    for req in req_fields:
        if req not in q:
            errors.append(f"缺少必填字段 '{req}'")
        elif q[req] is None or q[req] == '':
            errors.append(f"必填字段 '{req}' 为空")
    
    # answer bounds check
    answer = q.get('answer', [])
    options = q.get('options', []) or q.get('optionsImage', []) or q.get('optionList', [])
    if isinstance(answer, list) and options:
        for ai in answer:
            if isinstance(ai, int) and (ai < 0 or ai >= len(options)):
                errors.append(f"answer索引{ai}超出options范围(0-{len(options)-1})")
    
    # ability tags
    abilities = q.get('ability', [])
    if not abilities:
        warnings.append("能力标签为空，需补充")
    
    # Handle "¥¥" delimiter in P7 data
    cleaned_abilities = []
    for a in abilities:
        if isinstance(a, str) and '¥¥' in a:
            cleaned_abilities.extend(a.split('¥¥'))
        else:
            cleaned_abilities.append(a)
    
    for a in cleaned_abilities:
        a_stripped = a.strip()
        if a_stripped in ALL_TAGS:
            continue
        # Check if it's an old-style tag
        if '听觉' in a_stripped or '听力' in a_stripped:
            tag_issues.append(f"'{a_stripped}' 含'听觉/听力'非标准标签，需替换")
        elif a_stripped in TAG_MAP:
            tag_issues.append(f"'{a_stripped}' → '{TAG_MAP[a_stripped]}'")
        elif a_stripped:
            tag_issues.append(f"'{a_stripped}' 不在标准标签库中")
    
    # explanation
    expl = q.get('explanation', '')
    if expl is None or expl == '':
        warnings.append("解析为空，需补充")
    elif isinstance(expl, str) and len(expl) < 10:
        warnings.append(f"解析过短（{len(expl)}字）")
    
    return errors, warnings, tag_issues

def audit_record(fields, record_id, table_name):
    jd_str = fields.get('jsonData', '{}')
    sid = fields.get('题目集合 ID', '') or ''
    
    # Parse JSON
    try:
        jd = json.loads(jd_str)
    except json.JSONDecodeError as e:
        return [f"jsonData JSON解析失败: {str(e)}"], [], [], {}, "unknown", 0, 0, sid
    
    first = jd.get('first', {})
    second = jd.get('second', {})
    qs1 = first.get('questionSet', [])
    qs2 = second.get('questionSet', [])
    ftype = first.get('type', '') or second.get('type', '')
    
    req_fields = TYPE_FIELDS.get(ftype, ["question", "options", "answer", "ability", "explanation"])
    
    errors = []
    warnings = []
    notes = []
    
    if not qs1 and not qs2:
        errors.append("first和second题组均为空（无题目数据）")
    elif qs1 and not qs2:
        notes.append("只有一道题组（first），缺少second题组")
    elif qs2 and not qs1:
        notes.append("只有一道题组（second），缺少first题组")
    
    all_tag_issues = []
    for set_name, qset in [('first', qs1), ('second', qs2)]:
        for qi, q in enumerate(qset):
            prefix = f"{set_name}[{qi}]"
            q_errors, q_warnings, q_tag_issues = audit_question(q, req_fields, ftype)
            for e in q_errors:
                errors.append(f"{prefix}: {e}")
            for w in q_warnings:
                warnings.append(f"{prefix}: {w}")
            all_tag_issues.extend(q_tag_issues)
    
    # Deduplicate and count tag issues
    tag_summary = {}
    for ti in all_tag_issues:
        tag_summary[ti] = tag_summary.get(ti, 0) + 1
    
    return errors, warnings, notes, tag_summary, ftype, len(qs1), len(qs2), sid

def format_result(errors, warnings, notes, tag_summary, ftype, n1, n2, sid):
    lines = []
    
    if errors:
        lines.append(f"❌ 审校发现问题（{len(errors)}项错误）")
    elif warnings or notes:
        lines.append(f"⚠️ 审校通过（{len(warnings)}项建议 + {len(notes)}项备注）")
    else:
        lines.append("✅ 审校通过（无问题）")
    
    lines.append(f"题型：{ftype} | 题组：first={n1}题 second={n2}题")
    
    for n in notes:
        lines.append(f"📝 备注：{n}")
    
    if errors:
        lines.append(f"\n🔴 必须修改：")
        for e in errors:
            lines.append(f"  - {e}")
    
    if tag_summary:
        lines.append(f"\n🟡 能力标签修正建议：")
        for tag, count in sorted(tag_summary.items()):
            lines.append(f"  - {tag}（{count}处）")
    
    if warnings:
        lines.append(f"\n🟡 其他建议：")
        for w in warnings:
            lines.append(f"  - {w}")
    
    return '\n'.join(lines)

# ===== Main =====
targets = {
    "听力-P1": {"table_id": "tbliZAhcc9C43B23", "file": "/tmp/listening_P1.json"},
    "听力-P2": {"table_id": "tblzTLNH7f13uWQN", "file": "/tmp/listening_P2.json"},
    "听力-P4": {"table_id": "tblVmeDtBDKsAEfz", "file": "/tmp/listening_P4.json"},
    "听力-P7": {"table_id": "tbly9SvPEa44k3yX", "file": "/tmp/listening_P7.json"},
}

all_results = []
skip_count = 0

for name, config in targets.items():
    try:
        with open(config['file']) as f:
            data = json.load(f)
    except FileNotFoundError:
        print(f"⚠️ {name}: 数据文件未找到")
        continue
    
    if data.get('code') != 0:
        print(f"⚠️ {name}: API error")
        continue
    
    for item in data['data']['items']:
        fields = item.get('fields', {})
        sid = fields.get('题目集合 ID', '') or ''
        
        # Skip 010199
        if '010199' in str(sid):
            skip_count += 1
            continue
        
        # Skip empty jsonData
        jd_str = fields.get('jsonData', '{}')
        if not jd_str or jd_str == 'None':
            continue
        
        if not sid:
            continue
        
        errors, warnings, notes, tag_summary, ftype, n1, n2, sid2 = audit_record(fields, item['record_id'], name)
        result_text = format_result(errors, warnings, notes, tag_summary, ftype, n1, n2, sid)
        
        print(f"\n{'='*60}")
        print(f"{name} | ID={sid}")
        print(f"{'='*60}")
        print(result_text)
        
        all_results.append({
            "table_name": name,
            "table_id": config['table_id'],
            "record_id": item['record_id'],
            "sid": sid,
            "audit_text": result_text,
            "has_errors": len(errors) > 0,
        })

print(f"\n\n===== 审校汇总 =====")
print(f"总记录数: {len(all_results)}")
print(f"跳过(010199): {skip_count}")

# Save results
with open("/tmp/listening_audit_results.json", "w") as f:
    json.dump(all_results, f, ensure_ascii=False, indent=2)
print(f"结果已保存到 /tmp/listening_audit_results.json")

# Also print compact summary
for r in all_results:
    status = "❌" if r['has_errors'] else "⚠️" if "备注" in r['audit_text'] else "✅"
    print(f"{status} {r['table_name']:10s} | ID={r['sid']:10s} | {r['audit_text'].split(chr(10))[0]}")
