import argparse
import json
import os
import re
import sys
from pathlib import Path

sys.stdout.reconfigure(encoding='utf-8')
sys.stderr.reconfigure(encoding='utf-8')

PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent.parent
DEFAULT_CONFIG_DIR = PROJECT_ROOT / "Assets" / "Resources" / "Resources_moved" / "config"
DEFAULT_OUTPUT = Path(__file__).resolve().parent / "ConfigLinkData.json"
DEFAULT_TABLE_INFO = Path(__file__).resolve().parent / "table_info.json"


def parse_args():
    parser = argparse.ArgumentParser(description="ConfigLinkViewer 配置表联动关系自动生成")
    parser.add_argument("--config-dir", type=str, default=None,
                        help="JSON 配置导出目录 (默认: Assets/Resources/Resources_moved/config)")
    parser.add_argument("--output", type=str, default=None,
                        help="输出 ConfigLinkData.json 路径")
    parser.add_argument("--table-info", type=str, default=None,
                        help="表信息配置 JSON 路径 (默认: table_info.json)")
    return parser.parse_args()


def load_table_info(filepath):
    if filepath.exists():
        with open(filepath, "r", encoding="utf-8") as f:
            data = json.load(f)
        entries = data.get("entries", [])
        return {
            entry["name"]: (entry.get("displayName", entry["name"]), entry.get("description", ""))
            for entry in entries
        }
    return {}


TABLE_NAME_TO_CN = {
    "hero": "英雄",
    "enemy": "敌人",
    "equip": "装备",
    "prop": "道具",
    "skill": "技能",
    "buff": "增益效果",
    "attribute": "属性",
    "quest": "任务",
    "player": "玩家",
    "rune": "符文",
    "recharge": "充值",
    "checkpointreward": "关卡奖励",
    "activity": "活动",
    "map_act": "地图波次1",
    "map_act2": "地图波次2",
    "map_act3": "地图波次3",
    "map_act4": "地图波次4",
    "fight_sample": "主线关卡",
    "fight_arena": "竞技场战斗",
    "fight_fb1": "副本1",
    "fight_fb2": "副本2",
    "fight_fb3": "副本3",
    "fight_fb4": "副本4",
    "map": "地图",
}


def load_json_file(filepath):
    try:
        with open(filepath, "r", encoding="utf-8-sig") as f:
            return json.load(f)
    except UnicodeDecodeError:
        with open(filepath, "r", encoding="utf-8") as f:
            return json.load(f)
    except json.JSONDecodeError:
        return []


def extract_fields_from_json(filepath):
    data = load_json_file(filepath)

    if isinstance(data, list) and len(data) > 0:
        return list(data[0].keys())
    elif isinstance(data, dict):
        return list(data.keys())
    return []


def detect_reward_format(values):
    if not values:
        return ""
    sample = ""
    for v in values[:5]:
        if isinstance(v, str):
            sample = v
            break
        elif isinstance(v, list) and len(v) > 0:
            for item in v[:3]:
                if isinstance(item, str):
                    sample = item
                    break
            if sample:
                break

    if not sample:
        return ""

    if re.match(r"^item_\d+_\d+$", sample):
        return "item_id_num"
    if re.match(r"^hero_\d+$", sample):
        return "hero_id"
    if re.match(r"^rune_\d+_\d+$", sample):
        return "item_id_num"
    if re.match(r"^equip_\d+_\d+$", sample):
        return "item_id_num"
    if re.match(r"^Hero_\d+$", sample):
        return "item_id_num"
    if re.match(r"^\d+_\d+_\d+_\d+$", sample):
        return "id_lv_count_delay"
    if re.match(r"^\d+_\d+_\d+$", sample):
        return "id_lv_num"
    return ""


def detect_consumes_format(values):
    if not values:
        return ""
    sample = ""
    for v in values[:5]:
        if isinstance(v, str):
            sample = v
            break
        elif isinstance(v, list) and len(v) > 0:
            for item in v[:3]:
                if isinstance(item, str):
                    sample = item
                    break
            if sample:
                break

    if not sample:
        return ""

    if re.match(r"^item_\d+_\d+$", sample):
        return "item_id_num"
    return ""


def detect_monster_format(values):
    if not values:
        return ""
    sample = ""
    for v in values[:5]:
        if isinstance(v, str):
            sample = v
            break
        elif isinstance(v, list) and len(v) > 0:
            for item in v[:3]:
                if isinstance(item, str):
                    sample = item
                    break
            if sample:
                break

    if not sample:
        return ""

    if re.match(r"^\d+_\d+_\d+_\d+(\.\d+)?$", sample):
        return "id_lv_count_delay"
    if re.match(r"^\d+_\d+_\d+$", sample):
        return "id_lv_num"
    return ""


def get_relation_for_target_id(table_name):
    mapping = {
        "herolevel": ("hero", "关联英雄ID"),
        "herostage": ("hero", "关联英雄ID"),
        "herolevelinternal": ("enemy", "关联敌人ID"),
        "enemylevel": ("enemy", "关联敌人ID"),
        "equiplevel": ("equip", "关联装备ID"),
        "equipstage": ("equip", "关联装备ID"),
        "playerlevel": ("player", "关联玩家ID"),
        "playerstage": ("player", "关联玩家ID"),
        "runelevel": ("rune", "关联符文ID"),
        "skilllevel": ("skill", "关联技能ID"),
        "buff": ("skill", "关联技能ID"),
        "map": ("map", "关联地图ID"),
        "map1": ("map", "关联地图ID"),
        "map2": ("map", "关联地图ID"),
        "map3": ("map", "关联地图ID"),
        "map_act": ("map", "关联地图ID"),
        "map_act2": ("map", "关联地图ID"),
        "map_act3": ("map", "关联地图ID"),
        "map_act4": ("map", "关联地图ID"),
        "test_map_act": ("map", "关联地图ID"),
        "trainbreak": ("prop", "关联训练突破ID"),
        "trainlevel": ("prop", "关联训练等级ID"),
    }
    if table_name in mapping:
        return mapping[table_name]
    return None


def build_relations(table_name, fields, sample_values):
    relations = []

    reward_fields = {
        "rewards", "rewards2", "pass_rewards", "activateRewards", "reward",
        "dailyQuestScoreRewards", "weeklyQuestScoreRewards", "achievementScoreRewards",
        "heroTujianRewards",
    }
    consume_fields = {"consumes", "lostConsumes"}
    monster_fields = {"monsters", "enemy_ids"}
    equip_fields = {"equips"}
    skill_fields = {"skill_ids", "skills"}
    hero_fields = {"hero_ids"}
    quest_fields = {"quest"}
    attr_fields = {"attr_id", "level_attr_id", "stage_attr_id"}
    shard_fields = {"shardItem"}
    compose_fields = {"compose"}
    next_fields = {"next"}
    recharge_fields = {"recharge_id"}
    product_fields = {"productId"}
    out_enemy_fields = {"out_enemy_config"}
    scene_fight_fields = {"fight_cf_name"}
    scene_map_fields = {"map_cf_name"}
    time_limit_fields = {"time_limit_boss"}

    for field in fields:
        if field == "target_id":
            result = get_relation_for_target_id(table_name)
            if result:
                target, desc = result
                relations.append({
                    "field": field,
                    "target": target,
                    "targetField": "id",
                    "format": "",
                    "description": desc,
                })
            continue

        if field == "activityId":
            relations.append({
                "field": field,
                "target": "activity",
                "targetField": "id",
                "format": "",
                "description": "所属活动ID",
            })
            continue

        if field == "reward_id":
            relations.append({
                "field": field,
                "target": "checkpointreward",
                "targetField": "id",
                "format": "",
                "description": "关卡奖励ID",
            })
            continue

        if field in reward_fields:
            fmt = detect_reward_format(sample_values.get(field, []))
            if not fmt:
                fmt = "item_id_num"

            desc_map = {
                "rewards": "奖励道具",
                "rewards2": "付费奖励道具",
                "pass_rewards": "首通奖励道具",
                "activateRewards": "激活奖励道具",
                "reward": "宝箱奖励道具",
            }
            desc = desc_map.get(field, f"{field}奖励道具")

            if table_name == "gacha" and field == "rewards":
                relations.append({
                    "field": field,
                    "target": "hero",
                    "targetField": "id",
                    "format": "hero_id",
                    "description": "召唤产出英雄(格式: hero_英雄ID)",
                })
            else:
                relations.append({
                    "field": field,
                    "target": "prop",
                    "targetField": "id",
                    "format": fmt,
                    "description": f"{desc}(格式: {fmt})" if fmt else desc,
                })
            continue

        if field in consume_fields:
            fmt = detect_consumes_format(sample_values.get(field, []))
            desc_map = {
                "consumes": "消耗道具",
                "lostConsumes": "失败损失道具",
            }
            desc = desc_map.get(field, field)
            relations.append({
                "field": field,
                "target": "prop",
                "targetField": "id",
                "format": fmt if fmt else "item_id_num",
                "description": f"{desc}(格式: item_id_num)" if fmt else f"{desc}(格式: item_id_num)",
            })
            continue

        if field in monster_fields:
            fmt = detect_monster_format(sample_values.get(field, []))
            desc_map = {
                "monsters": "怪物列表",
                "enemy_ids": "敌人列表",
            }
            desc = desc_map.get(field, field)
            format_desc = f"(格式: {fmt})" if fmt else ""
            relations.append({
                "field": field,
                "target": "enemy",
                "targetField": "id",
                "format": fmt,
                "description": f"{desc}{format_desc}",
            })
            continue

        if field in time_limit_fields:
            relations.append({
                "field": field,
                "target": "enemy",
                "targetField": "id",
                "format": "id_lv_num_hp",
                "description": "限时Boss(格式: 敌人ID_等级_数量_血量百分比)",
            })
            continue

        if field in equip_fields:
            relations.append({
                "field": field,
                "target": "equip",
                "targetField": "id",
                "format": "",
                "description": "装备槽位装备ID列表",
            })
            continue

        if field in skill_fields:
            relations.append({
                "field": field,
                "target": "skill",
                "targetField": "id",
                "format": "",
                "description": "技能ID列表",
            })
            continue

        if field in hero_fields:
            relations.append({
                "field": field,
                "target": "hero",
                "targetField": "id",
                "format": "",
                "description": "关联英雄ID列表",
            })
            continue

        if field in quest_fields:
            relations.append({
                "field": field,
                "target": "quest",
                "targetField": "id",
                "format": "",
                "description": "关联任务ID列表",
            })
            continue

        if field in attr_fields:
            relations.append({
                "field": field,
                "target": "attribute",
                "targetField": "id",
                "format": "",
                "description": "关联属性ID",
            })
            continue

        if field in shard_fields:
            relations.append({
                "field": field,
                "target": "prop",
                "targetField": "id",
                "format": "",
                "description": "碎片道具ID",
            })
            continue

        if field in compose_fields:
            relations.append({
                "field": field,
                "target": "prop",
                "targetField": "id",
                "format": "",
                "description": "合成材料道具ID列表",
            })
            continue

        if field in next_fields:
            relations.append({
                "field": field,
                "target": table_name,
                "targetField": "id",
                "format": "",
                "description": "下一个ID(自引用)",
            })
            continue

        if field in recharge_fields:
            relations.append({
                "field": field,
                "target": "recharge",
                "targetField": "id",
                "format": "",
                "description": "关联充值档位ID",
            })
            continue

        if field in product_fields:
            relations.append({
                "field": field,
                "target": "prop",
                "targetField": "id",
                "format": "",
                "description": "商品道具ID",
            })
            continue

        if field in out_enemy_fields:
            relations.append({
                "field": field,
                "target": "map_act",
                "targetField": "id",
                "format": "",
                "description": "出怪波次配置表名",
            })
            continue

        if field in scene_fight_fields:
            relations.append({
                "field": field,
                "target": "fight_sample",
                "targetField": "id",
                "format": "",
                "description": "关联战斗配置表名",
            })
            continue

        if field in scene_map_fields:
            relations.append({
                "field": field,
                "target": "map",
                "targetField": "id",
                "format": "",
                "description": "关联地图配置表名",
            })
            continue

        if re.match(r"^.+Id$", field) and field != "Id":
            prefix = field[:-2]
            for known_table in TABLE_NAME_TO_CN:
                if known_table.lower() == prefix.lower():
                    relations.append({
                        "field": field,
                        "target": known_table,
                        "targetField": "id",
                        "format": "",
                        "description": f"关联{TABLE_NAME_TO_CN[known_table]}ID",
                    })
                    break

    return relations


SUSPICIOUS_ID_PATTERNS = [
    (re.compile(r"^.+Id$"), "可能引用其他表的ID字段(驼峰)"),
    (re.compile(r"^.+_id$"), "可能引用其他表的ID字段(下划线)"),
    (re.compile(r"^.+_ids$"), "可能引用其他表的ID列表(下划线)"),
    (re.compile(r"^.+_Ids$"), "可能引用其他表的ID列表(驼峰)"),
]


def analyze_gaps(all_tables, table_fields_map):
    issues = []
    ai_prompt_parts = []

    tables_not_in_info = [t["name"] for t in all_tables if t["displayName"] == t["name"]]
    if tables_not_in_info:
        issues.append({
            "type": "missing_display_name",
            "severity": "warning",
            "title": "以下表缺少中文名和描述",
            "items": tables_not_in_info,
        })
        ai_prompt_parts.append(
            f"以下表缺少中文名和描述，请补全 displayName 和 description:\n"
            + "\n".join(f"  - {t}" for t in tables_not_in_info)
        )

    no_relation_tables = [t["name"] for t in all_tables if len(t["relations"]) == 0]
    if no_relation_tables:
        issues.append({
            "type": "no_relations",
            "severity": "info",
            "title": "以下表没有任何引用关系（可能是叶子表或需人工检查）",
            "items": no_relation_tables,
        })

    unrecognized_fields = []
    for table_name, fields in table_fields_map.items():
        table_entry = next((t for t in all_tables if t["name"] == table_name), None)
        if not table_entry:
            continue
        related_fields = {r["field"] for r in table_entry["relations"]}
        for field in fields:
            if field in related_fields:
                continue
            for pattern, desc in SUSPICIOUS_ID_PATTERNS:
                if pattern.match(field):
                    unrecognized_fields.append(f"  {table_name}.{field} - {desc}")
                    break

    if unrecognized_fields:
        issues.append({
            "type": "unrecognized_fields",
            "severity": "warning",
            "title": "以下字段可能是引用关系但脚本未能识别",
            "items": unrecognized_fields,
        })
        ai_prompt_parts.append(
            "以下字段可能是引用关系但脚本未能识别，请分析并补全 relations:\n"
            + "\n".join(unrecognized_fields)
        )

    tables_with_missing_fields = []
    for table in all_tables:
        if table["displayName"] == table["name"] and len(table["relations"]) == 0:
            fields = table_fields_map.get(table["name"], [])
            if fields:
                tables_with_missing_fields.append(
                    f"  {table['name']} (字段: {', '.join(fields[:8])}{'...' if len(fields) > 8 else ''})"
                )

    if tables_with_missing_fields:
        issues.append({
            "type": "fully_missing",
            "severity": "error",
            "title": "以下表完全未配置（无中文名、无描述、无引用关系）",
            "items": tables_with_missing_fields,
        })
        ai_prompt_parts.append(
            "以下表完全未配置，请补全 displayName、description 和 relations:\n"
            + "\n".join(tables_with_missing_fields)
        )

    return issues, ai_prompt_parts


def main():
    args = parse_args()

    config_dir = Path(args.config_dir) if args.config_dir else DEFAULT_CONFIG_DIR
    output_file = Path(args.output) if args.output else DEFAULT_OUTPUT
    table_info_file = Path(args.table_info) if args.table_info else DEFAULT_TABLE_INFO

    table_info = load_table_info(table_info_file)

    all_tables = []
    table_fields_map = {}

    json_files = sorted(config_dir.glob("*.json"))

    for filepath in json_files:
        table_name = filepath.stem
        fields = extract_fields_from_json(filepath)
        if not fields:
            continue

        table_fields_map[table_name] = fields

        sample_values = {}
        data = load_json_file(filepath)

        if isinstance(data, list) and len(data) > 0:
            first_row = data[0]
            for field in fields:
                if field in first_row:
                    val = first_row[field]
                    if isinstance(val, list):
                        sample_values[field] = val
                    else:
                        sample_values[field] = [val] if val is not None else []

        display_name, description = table_info.get(table_name, (table_name, ""))
        relations = build_relations(table_name, fields, sample_values)

        all_tables.append({
            "name": table_name,
            "displayName": display_name,
            "description": description,
            "fileExtension": ".xlsx",
            "relations": relations,
        })

    txt_files = sorted(config_dir.glob("*.txt"))
    for filepath in txt_files:
        table_name = filepath.stem
        if table_name in table_info:
            display_name, description = table_info[table_name]
        else:
            display_name, description = table_name, ""
        all_tables.append({
            "name": table_name,
            "displayName": display_name,
            "description": description,
            "fileExtension": ".txt",
            "relations": [],
        })

    output = {"tables": all_tables}
    output_file.parent.mkdir(parents=True, exist_ok=True)
    with open(output_file, "w", encoding="utf-8") as f:
        json.dump(output, f, ensure_ascii=False, indent=4)

    total_tables = len(all_tables)
    total_relations = sum(len(t['relations']) for t in all_tables)
    tables_with_rels = sum(1 for t in all_tables if t['relations'])

    print("=" * 60)
    print("  ConfigLinkData.json 生成完成")
    print("=" * 60)
    print(f"  输出文件: {output_file}")
    print(f"  总表数: {total_tables}")
    print(f"  有引用关系的表: {tables_with_rels}")
    print(f"  总引用关系数: {total_relations}")
    print()

    issues, ai_prompt_parts = analyze_gaps(all_tables, table_fields_map)

    if not issues:
        print("  所有表均已完整配置，无需要补全的内容。")
    else:
        print("-" * 60)
        print("  查漏补缺报告")
        print("-" * 60)
        for issue in issues:
            severity_icon = {"error": "[!]", "warning": "[*]", "info": "[i]"}.get(issue["severity"], "")
            print(f"\n  {severity_icon} {issue['title']} ({len(issue['items'])}项)")
            for item in issue["items"]:
                print(f"    {item}")

        if ai_prompt_parts:
            print()
            print("=" * 60)
            print("  AI 补全提示词（可复制发送给 AI）")
            print("=" * 60)
            print()
            print("我需要你帮助维护配置表联动查看器的配置文件。")
            print()
            print(f"当前目录：{output_file.parent}")
            print()
            print("请：")
            print("1. 读取 ConfigLinkData.json，分析所有表的配置情况")
            print("2. 找出缺少中文名称（displayName == name）或描述为空的表，补充中文名称和描述")
            print("3. 分析字段引用关系，为缺少联动关系的表添加 relations")
            print("4. 对于 target_id 字段，通常引用对应的基础表（如 herolevel.target_id -> hero）")
            print("5. 对于 xxxId/xxx_id 字段，根据前缀推断目标表（如 itemId -> prop）")
            print("6. 同时更新 table_info.json（中文名称）和 ConfigLinkData.json（完整配置）")
            print("7. 输出修改摘要")
            print()
            print("需要处理的内容：")
            print()
            for part in ai_prompt_parts:
                print(part)
                print()
            print("注意：")
            print("- displayName 应该是简洁的中文名称（如\"英雄\"、\"装备\"）")
            print("- description 应该是清晰的功能描述（如\"英雄基础属性配置\"）")
            print("- relations 字段格式：{\"field\": \"字段名\", \"target\": \"目标表名\", \"targetField\": \"id\", \"description\": \"关联描述\"}")
            print("- 保持 JSON 格式正确，不要添加多余逗号")
            print("- table_info.json 只需更新 displayName 和 description")
            print("- ConfigLinkData.json 需要更新 displayName、description 和 relations")

    print()


if __name__ == "__main__":
    main()
