#!/usr/bin/env python3
"""
identify_template.py

给模板源目录颁发或校准身份信息，直接修改源目录的 __teacher__.json。
不做任何文件移动，可单独运行。

写入字段：
  _id       : 8位十六进制，首次颁发，后续不变
  任务类别  : 校准后的系列（A/B/C）
  任务编号  : 校准后的3位编号（100起）

用法：
    python3 identify_template.py <模板目录>
"""
import json
import re
import secrets
import sys
from pathlib import Path

ROOT = Path(__file__).resolve().parent.parent
TEMPLATES_DIR = ROOT / 'templates'


def load_json(path: Path) -> dict:
    try:
        return json.loads(path.read_text(encoding='utf-8'))
    except Exception:
        return {}


def save_json(path: Path, data: dict):
    path.write_text(json.dumps(data, ensure_ascii=False, indent=2) + '\n', encoding='utf-8')


def gen_id() -> str:
    return secrets.token_hex(4)  # 8位十六进制


def normalize_category(raw) -> str:
    cat = str(raw).upper().strip()
    if cat not in {'A', 'B', 'C', 'D', 'E'}:
        raise ValueError(f'任务类别只能是 A、B、C、D、E，当前: {cat}')
    return cat


def get_latest_version_num(folder: Path) -> int:
    """返回 folder 下最大的版本号，没有则返回 0"""
    max_v = 0
    for d in folder.iterdir():
        if d.is_dir():
            m = re.match(r'^v(\d+)$', d.name)
            if m:
                max_v = max(max_v, int(m.group(1)))
    return max_v


def scan_templates(templates_dir: Path):
    """
    扫描 templates/ 下所有已入库模板。
    返回：
      id_map     : { _id -> {'folder': Path, 'version': int} }
      number_map : { category -> { number(int) -> _id } }
    """
    id_map = {}
    number_map = {}
    pattern = re.compile(r'^([a-zA-Z])(\d{3})_')

    if not templates_dir.exists():
        return id_map, number_map

    for folder in templates_dir.iterdir():
        if not folder.is_dir():
            continue
        m = pattern.match(folder.name)
        if not m:
            continue

        version_num = get_latest_version_num(folder)
        if version_num == 0:
            continue

        version_dir = folder / f'v{version_num}'
        teacher = load_json(version_dir / '__teacher__.json')
        tid = teacher.get('_id')
        if not tid:
            continue

        cat = m.group(1).upper()
        num = int(m.group(2))

        id_map[tid] = {'folder': folder, 'version': version_num}
        number_map.setdefault(cat, {})[num] = tid

    return id_map, number_map


def calibrate_number(category: str, desired: int, number_map: dict, own_id: str) -> int:
    """
    校准编号：
    - 宣称的编号不存在，或已属于自己 → 合法，直接用
    - 已被别人占用 → 找最小可用编号（>=100）
    """
    used = number_map.get(category, {})
    owner = used.get(desired)
    if owner is None or owner == own_id:
        return desired
    # 冲突，找最小可用
    for num in range(100, 1000):
        if num not in used or used[num] == own_id:
            return num
    raise RuntimeError(f'{category} 类编号已用尽')


def main():
    if len(sys.argv) < 2:
        print('用法: python3 identify_template.py <模板目录>')
        sys.exit(1)

    source_dir = Path(sys.argv[1]).expanduser().resolve()
    teacher_path = source_dir / '__teacher__.json'

    if not teacher_path.exists():
        print(f'❌ 找不到 __teacher__.json: {teacher_path}')
        sys.exit(1)

    teacher = load_json(teacher_path)
    id_map, number_map = scan_templates(TEMPLATES_DIR)

    # ── 1. _id 与版本号 ────────────────────────────────────────────────────
    tid = teacher.get('_id', '').strip()
    in_templates = tid and tid in id_map

    if not tid:
        tid = gen_id()
        new_version = 1
        print(f'🆔 颁发新 ID: {tid}  版本: v1')
    elif not in_templates:
        new_version = 1
        print(f'🆔 已有 ID {tid}，首次入库  版本: v1')
    else:
        old_version = id_map[tid]['version']
        new_version = old_version + 1
        print(f'🔄 更新 ID {tid}  版本: v{old_version} → v{new_version}')

    # ── 2. 校准 任务类别 + 任务编号 ────────────────────────────────────────
    try:
        category = normalize_category(teacher.get('任务类别', ''))
    except ValueError as e:
        print(f'❌ {e}')
        sys.exit(1)

    try:
        desired = int(str(teacher.get('任务编号', '100')))
    except ValueError:
        desired = 100

    calibrated = calibrate_number(category, desired, number_map, tid)
    if calibrated != desired:
        print(f'⚠️  编号冲突：{category}{desired:03d} 已被占用，校准为 {category}{calibrated:03d}')

    # ── 3. 写回 __teacher__.json ───────────────────────────────────────────
    teacher['_id'] = tid
    teacher['任务类别'] = category
    teacher['任务编号'] = f'{calibrated:03d}'
    save_json(teacher_path, teacher)

    print(f'✅ 已写回: {teacher_path}')
    print(f'   _id={tid}, _version=v{new_version}, 分类={category}{calibrated:03d}')


if __name__ == '__main__':
    main()
