#!/usr/bin/env python3
"""
Task ID 리넘버링 스크립트
task-9991.1~task-10000.1 → task-1183.1~task-1192.1

Usage:
    python3 renumber_task_ids.py --dry-run   # 변경 계획만 출력
    python3 renumber_task_ids.py             # 실제 변경 수행
"""

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

WORKSPACE = Path("/home/jay/workspace")
MEMORY = WORKSPACE / "memory"

# 리넘버링 매핑 (old → new)
MAPPING = {
    "task-9991.1": "task-1183.1",
    "task-9992.1": "task-1184.1",
    "task-9993.1": "task-1185.1",
    "task-9994.1": "task-1186.1",
    "task-9995.1": "task-1187.1",
    "task-9996.1": "task-1188.1",
    "task-9997.1": "task-1189.1",
    "task-9998.1": "task-1190.1",
    "task-9999.1": "task-1191.1",
    "task-10000.1": "task-1192.1",
    # task-10001.1, task-10002.1 은 SKIP (running 중)
}

errors = []
changes = []


def log(msg: str):
    print(msg)


def record_change(kind: str, old: str, new: str):
    changes.append((kind, old, new))
    log(f"  [{kind}] {old} → {new}")


def record_error(msg: str):
    errors.append(msg)
    log(f"  [ERROR] {msg}")


# ────────────────────────────────────────────────
# 1. task-timers.json
# ────────────────────────────────────────────────
def renumber_timers(dry_run: bool):
    log("\n[1] task-timers.json 처리")
    timer_file = MEMORY / "task-timers.json"
    lock_file_path = MEMORY / ".task-timers.lock"
    lock_file_path.parent.mkdir(parents=True, exist_ok=True)

    if not timer_file.exists():
        record_error(f"파일 없음: {timer_file}")
        return

    lock_file = open(lock_file_path, "w")
    try:
        fcntl.flock(lock_file, fcntl.LOCK_EX)

        with open(timer_file, "r") as f:
            data = json.load(f)

        tasks = data.get("tasks", {})
        new_tasks = {}
        modified = False

        for key, val in tasks.items():
            if key in MAPPING:
                new_key = MAPPING[key]
                record_change("timer-key", key, new_key)
                # task_id 필드도 교체
                if isinstance(val, dict) and val.get("task_id") == key:
                    val = dict(val)
                    val["task_id"] = new_key
                    record_change("timer-field:task_id", key, new_key)
                new_tasks[new_key] = val
                modified = True
            else:
                new_tasks[key] = val

        if modified:
            data["tasks"] = new_tasks
            if not dry_run:
                with open(timer_file, "w") as f:
                    json.dump(data, f, ensure_ascii=False, indent=2)
                log(f"  → 저장 완료: {timer_file}")
            else:
                log(f"  → [dry-run] 실제 저장 생략")
        else:
            log(f"  → 변경 없음")
    except (json.JSONDecodeError, OSError) as e:
        record_error(f"task-timers.json 처리 실패: {e}")
    finally:
        fcntl.flock(lock_file, fcntl.LOCK_UN)
        lock_file.close()


# ────────────────────────────────────────────────
# 2. Task 파일 (tasks/ 디렉토리)
# ────────────────────────────────────────────────
def renumber_task_files(dry_run: bool):
    log("\n[2] Task 파일 처리 (tasks/)")
    tasks_dir = MEMORY / "tasks"
    # 9991~9993은 task 파일 없음(테스트 엔트리), 9994~10000만 처리
    rename_targets = {k: v for k, v in MAPPING.items() if k not in ("task-9991.1", "task-9992.1", "task-9993.1")}

    for old_id, new_id in rename_targets.items():
        old_path = tasks_dir / f"{old_id}.md"
        new_path = tasks_dir / f"{new_id}.md"
        if not old_path.exists():
            log(f"  [SKIP] {old_path.name} (없음)")
            continue
        # 파일 내용 치환
        content = old_path.read_text()
        new_content = content
        for oid, nid in MAPPING.items():
            new_content = new_content.replace(oid, nid)
        if new_content != content:
            record_change("task-content", old_id, new_id)
        # 파일 이름 변경
        record_change("task-rename", str(old_path), str(new_path))
        if not dry_run:
            new_path.write_text(new_content)
            old_path.unlink()
            log(f"  → 저장 및 이름 변경 완료")
        else:
            log(f"  → [dry-run] 생략")


# ────────────────────────────────────────────────
# 3. Report 파일 (reports/ 디렉토리)
# ────────────────────────────────────────────────
def renumber_report_files(dry_run: bool):
    log("\n[3] Report 파일 처리 (reports/)")
    reports_dir = MEMORY / "reports"
    rename_targets = {k: v for k, v in MAPPING.items() if k not in ("task-9991.1", "task-9992.1", "task-9993.1")}

    for old_id, new_id in rename_targets.items():
        old_path = reports_dir / f"{old_id}.md"
        new_path = reports_dir / f"{new_id}.md"
        if not old_path.exists():
            log(f"  [SKIP] {old_path.name} (없음)")
            continue
        content = old_path.read_text()
        new_content = content
        for oid, nid in MAPPING.items():
            new_content = new_content.replace(oid, nid)
        if new_content != content:
            record_change("report-content", old_id, new_id)
        record_change("report-rename", str(old_path), str(new_path))
        if not dry_run:
            new_path.write_text(new_content)
            old_path.unlink()
            log(f"  → 저장 및 이름 변경 완료")
        else:
            log(f"  → [dry-run] 생략")


# ────────────────────────────────────────────────
# 4. Event 파일 (events/ 디렉토리)
# ────────────────────────────────────────────────
def renumber_event_files(dry_run: bool):
    log("\n[4] Event 파일 처리 (events/)")
    events_dir = MEMORY / "events"

    # 이름 변경 대상 파일 목록 (명세에서 지정)
    event_renames = [
        ("task-9991.1.done.clear", "task-1183.1.done.clear"),
        ("task-9992.1.done.clear", "task-1184.1.done.clear"),
        ("task-9993.1.done.clear", "task-1185.1.done.clear"),
        ("task-9994.1.completion.txt", "task-1186.1.completion.txt"),
        ("task-9994.1.done.acked", "task-1186.1.done.acked"),
        ("task-9994.1.done.notified", "task-1186.1.done.notified"),
        ("task-9995.1.completion.txt", "task-1187.1.completion.txt"),
        ("task-9995.1.done.acked", "task-1187.1.done.acked"),
        ("task-9995.1.done.notified", "task-1187.1.done.notified"),
        ("task-9996.1.completion.txt", "task-1188.1.completion.txt"),
        ("task-9996.1.done.acked", "task-1188.1.done.acked"),
        ("task-9996.1.done.notified", "task-1188.1.done.notified"),
        ("task-9997.1.completion.txt", "task-1189.1.completion.txt"),
        ("task-9997.1.done.acked", "task-1189.1.done.acked"),
        ("task-9997.1.done.notified", "task-1189.1.done.notified"),
        ("task-9998.1.completion.txt", "task-1190.1.completion.txt"),
        ("task-9998.1.done.acked", "task-1190.1.done.acked"),
        ("task-9998.1.done.notified", "task-1190.1.done.notified"),
        ("task-9999.1.completion.txt", "task-1191.1.completion.txt"),
        ("task-9999.1.done.acked", "task-1191.1.done.acked"),
        ("task-9999.1.done.notified", "task-1191.1.done.notified"),
        ("task-10000.1.completion.txt", "task-1192.1.completion.txt"),
        ("task-10000.1.done.acked", "task-1192.1.done.acked"),
        ("task-10000.1.done.notified", "task-1192.1.done.notified"),
    ]

    for old_name, new_name in event_renames:
        old_path = events_dir / old_name
        new_path = events_dir / new_name
        if not old_path.exists():
            log(f"  [SKIP] {old_name} (없음)")
            continue
        # completion.txt는 내용 치환
        if old_name.endswith(".completion.txt"):
            content = old_path.read_text()
            new_content = content
            for oid, nid in MAPPING.items():
                new_content = new_content.replace(oid, nid)
            if new_content != content:
                record_change("event-content", old_name, new_name)
            record_change("event-rename", str(old_path), str(new_path))
            if not dry_run:
                new_path.write_text(new_content)
                old_path.unlink()
                log(f"  → 저장 및 이름 변경 완료")
            else:
                log(f"  → [dry-run] 생략")
        else:
            # .done.clear, .done.acked, .done.notified → rename only (내용 보존)
            record_change("event-rename-only", str(old_path), str(new_path))
            if not dry_run:
                old_path.rename(new_path)
                log(f"  → 이름 변경 완료 (내용 보존)")
            else:
                log(f"  → [dry-run] 생략")


# ────────────────────────────────────────────────
# 5. Checkpoint 파일 (checkpoints/ 디렉토리)
# ────────────────────────────────────────────────
def renumber_checkpoint_files(dry_run: bool):
    log("\n[5] Checkpoint 파일 처리 (checkpoints/)")
    checkpoints_dir = MEMORY / "checkpoints"
    renames = [("task-9997.1.md", "task-1189.1.md")]
    for old_name, new_name in renames:
        old_path = checkpoints_dir / old_name
        new_path = checkpoints_dir / new_name
        if not old_path.exists():
            log(f"  [SKIP] {old_name} (없음)")
            continue
        content = old_path.read_text()
        new_content = content
        for oid, nid in MAPPING.items():
            new_content = new_content.replace(oid, nid)
        if new_content != content:
            record_change("checkpoint-content", old_name, new_name)
        record_change("checkpoint-rename", str(old_path), str(new_path))
        if not dry_run:
            new_path.write_text(new_content)
            old_path.unlink()
            log(f"  → 저장 및 이름 변경 완료")
        else:
            log(f"  → [dry-run] 생략")


# ────────────────────────────────────────────────
# 6. Meeting 파일 (meetings/ 디렉토리)
# ────────────────────────────────────────────────
def renumber_meeting_files(dry_run: bool):
    log("\n[6] Meeting 파일 처리 (meetings/)")
    meetings_dir = MEMORY / "meetings"
    renames = [
        ("task-9997.1-cycle1.md", "task-1189.1-cycle1.md"),
        ("task-9997.1-cycle2.md", "task-1189.1-cycle2.md"),
        ("task-9997.1-cycle3.md", "task-1189.1-cycle3.md"),
    ]
    for old_name, new_name in renames:
        old_path = meetings_dir / old_name
        new_path = meetings_dir / new_name
        if not old_path.exists():
            log(f"  [SKIP] {old_name} (없음)")
            continue
        content = old_path.read_text()
        new_content = content
        for oid, nid in MAPPING.items():
            new_content = new_content.replace(oid, nid)
        if new_content != content:
            record_change("meeting-content", old_name, new_name)
        record_change("meeting-rename", str(old_path), str(new_path))
        if not dry_run:
            new_path.write_text(new_content)
            old_path.unlink()
            log(f"  → 저장 및 이름 변경 완료")
        else:
            log(f"  → [dry-run] 생략")


# ────────────────────────────────────────────────
# 7. Team 파일 (teams/dev1/ 디렉토리)
# ────────────────────────────────────────────────
def renumber_team_files(dry_run: bool):
    log("\n[7] Team 파일 처리 (teams/dev1/)")
    dev1_dir = WORKSPACE / "teams" / "dev1"
    renames = [
        ("task-9997.1-implementation-plan.md", "task-1189.1-implementation-plan.md"),
        ("task-9997.1-design.md", "task-1189.1-design.md"),
    ]
    for old_name, new_name in renames:
        old_path = dev1_dir / old_name
        new_path = dev1_dir / new_name
        if not old_path.exists():
            log(f"  [SKIP] {old_name} (없음)")
            continue
        content = old_path.read_text()
        new_content = content
        for oid, nid in MAPPING.items():
            new_content = new_content.replace(oid, nid)
        if new_content != content:
            record_change("team-content", old_name, new_name)
        record_change("team-rename", str(old_path), str(new_path))
        if not dry_run:
            new_path.write_text(new_content)
            old_path.unlink()
            log(f"  → 저장 및 이름 변경 완료")
        else:
            log(f"  → [dry-run] 생략")


# ────────────────────────────────────────────────
# 8. Daily log 파일 내용 치환
# ────────────────────────────────────────────────
def renumber_daily_log(dry_run: bool):
    log("\n[8] Daily log 파일 내용 치환 (daily/2026-03-28.md)")
    daily_file = MEMORY / "daily" / "2026-03-28.md"
    if not daily_file.exists():
        record_error(f"파일 없음: {daily_file}")
        return

    content = daily_file.read_text()
    new_content = content
    for oid, nid in MAPPING.items():
        if oid in new_content:
            record_change("daily-content", oid, nid)
            new_content = new_content.replace(oid, nid)

    # task-10001.1은 치환하지 않음 (running 중) — 매핑에 없으므로 자동 보존
    if new_content == content:
        log(f"  → 변경 없음")
    else:
        if not dry_run:
            daily_file.write_text(new_content)
            log(f"  → 저장 완료: {daily_file}")
        else:
            log(f"  → [dry-run] 실제 저장 생략")


# ────────────────────────────────────────────────
# 메인
# ────────────────────────────────────────────────
def main():
    parser = argparse.ArgumentParser(description="Task ID 리넘버링 스크립트")
    parser.add_argument("--dry-run", action="store_true", help="변경 계획만 출력 (실제 변경 없음)")
    args = parser.parse_args()

    dry_run = args.dry_run
    mode = "DRY-RUN" if dry_run else "실행"
    log(f"{'='*60}")
    log(f"Task ID 리넘버링 스크립트 [{mode}]")
    log(f"{'='*60}")
    log(f"매핑:")
    for oid, nid in MAPPING.items():
        log(f"  {oid} → {nid}")

    renumber_timers(dry_run)
    renumber_task_files(dry_run)
    renumber_report_files(dry_run)
    renumber_event_files(dry_run)
    renumber_checkpoint_files(dry_run)
    renumber_meeting_files(dry_run)
    renumber_team_files(dry_run)
    renumber_daily_log(dry_run)

    log(f"\n{'='*60}")
    log(f"결과 요약")
    log(f"{'='*60}")
    log(f"총 변경 항목: {len(changes)}")
    log(f"오류 수: {len(errors)}")
    if errors:
        log(f"\n오류 목록:")
        for e in errors:
            log(f"  - {e}")
    if dry_run:
        log("\n[dry-run 완료] 실제 변경하려면 --dry-run 없이 실행하세요.")
    else:
        log("\n[실행 완료]")

    return 0 if not errors else 1


if __name__ == "__main__":
    sys.exit(main())
