#!/usr/bin/env python3
"""todo.json CRUD 관리 스크립트.

모든 todo.json 조작은 이 스크립트를 통해서만 수행한다.
issue-040 유실 사고 (JSON 구조 오류) 방지용.

Usage:
    python3 todo-manager.py list [--project NAME] [--status STATUS]
    python3 todo-manager.py show ISSUE_ID
    python3 todo-manager.py add --project NAME --title TITLE [OPTIONS]
    python3 todo-manager.py update ISSUE_ID [--status STATUS] [--priority PRIO] [--title TITLE]
    python3 todo-manager.py remove ISSUE_ID [--force]
    python3 todo-manager.py sub-add ISSUE_ID --title TITLE
    python3 todo-manager.py sub-done ISSUE_ID --index IDX --task-id TASK_ID
    python3 todo-manager.py sub-done ISSUE_ID --match TEXT --task-id TASK_ID
    python3 todo-manager.py link ISSUE_ID TASK_ID
"""

from __future__ import annotations

import argparse
import json
import sys
from datetime import datetime

import todo_utils
from todo_utils import find_issue, get_next_id, load_todo, print_json, save_todo


def cmd_list(args: argparse.Namespace) -> None:
    """이슈 목록 조회."""
    data = load_todo()
    issues = data.get("issues", [])

    # 필터링
    if args.project:
        issues = [i for i in issues if i.get("project") == args.project]
    if args.status:
        issues = [i for i in issues if i.get("status") == args.status]

    result = []
    for i in issues:
        result.append(
            {
                "id": i.get("id"),
                "project": i.get("project"),
                "title": i.get("title"),
                "status": i.get("status"),
                "priority": i.get("priority"),
            }
        )

    print_json(result, pretty=not args.json)


def cmd_show(args: argparse.Namespace) -> None:
    """이슈 상세 조회."""
    data = load_todo()
    issue = find_issue(data, args.issue_id)

    if not issue:
        print(f"Error: Issue '{args.issue_id}' not found", file=sys.stderr)
        sys.exit(1)

    print_json(issue, pretty=not args.json)


def cmd_add(args: argparse.Namespace) -> None:
    """이슈 추가."""
    data = load_todo()

    new_issue = {
        "id": get_next_id(data),
        "project": args.project,
        "title": args.title,
        "description": args.description or "",
        "priority": args.priority or "medium",
        "status": args.status or "pending",
        "created_at": datetime.now().isoformat(),
        "completed_at": None,
        "linked_tasks": [],
        "sub_items": [],
    }

    data["issues"].append(new_issue)
    save_todo(data)

    print_json({"success": True, "id": new_issue["id"]}, pretty=not args.json)


def cmd_update(args: argparse.Namespace) -> None:
    """이슈 수정."""
    data = load_todo()
    issue = find_issue(data, args.issue_id)

    if not issue:
        print(f"Error: Issue '{args.issue_id}' not found", file=sys.stderr)
        sys.exit(1)

    updated = []
    if args.status:
        issue["status"] = args.status
        updated.append("status")
        if args.status == "done":
            issue["completed_at"] = datetime.now().isoformat()
    if args.priority:
        issue["priority"] = args.priority
        updated.append("priority")
    if args.title:
        issue["title"] = args.title
        updated.append("title")

    save_todo(data)
    print_json({"success": True, "updated": updated}, pretty=not args.json)


def cmd_remove(args: argparse.Namespace) -> None:
    """이슈 삭제."""
    data = load_todo()
    issue = find_issue(data, args.issue_id)

    if not issue:
        print(f"Error: Issue '{args.issue_id}' not found", file=sys.stderr)
        sys.exit(1)

    # 확인 메시지
    if not args.force:
        print(f"Remove issue '{args.issue_id}': {issue.get('title')}?")
        resp = input("Confirm [y/N]: ").strip().lower()
        if resp != "y":
            print("Aborted")
            return

    # 백업 파일에 기록
    removed_data: dict = {"version": "1.0", "removed": []}
    if todo_utils.REMOVED_FILE.exists():
        with open(todo_utils.REMOVED_FILE, encoding=todo_utils.ENCODING) as f:
            removed_data = json.load(f)
    issue["removed_at"] = datetime.now().isoformat()
    removed_data["removed"].append(issue)
    with open(todo_utils.REMOVED_FILE, "w", encoding=todo_utils.ENCODING) as f:
        json.dump(removed_data, f, ensure_ascii=False, indent=2)

    # 삭제
    data["issues"] = [i for i in data["issues"] if i.get("id") != args.issue_id]
    save_todo(data)

    print_json({"success": True, "removed": args.issue_id}, pretty=not args.json)


def cmd_sub_add(args: argparse.Namespace) -> None:
    """sub_item 추가."""
    data = load_todo()
    issue = find_issue(data, args.issue_id)

    if not issue:
        print(f"Error: Issue '{args.issue_id}' not found", file=sys.stderr)
        sys.exit(1)

    sub_item = {"title": args.title, "done": False, "task_id": None}
    issue.setdefault("sub_items", []).append(sub_item)
    save_todo(data)

    print_json({"success": True, "index": len(issue["sub_items"]) - 1}, pretty=not args.json)


def cmd_sub_done(args: argparse.Namespace) -> None:
    """sub_item 완료 처리."""
    data = load_todo()
    issue = find_issue(data, args.issue_id)

    if not issue:
        print(f"Error: Issue '{args.issue_id}' not found", file=sys.stderr)
        sys.exit(1)

    sub_items = issue.get("sub_items", [])
    idx: int = -1  # sys.exit() 전 항상 재할당됨

    if args.index is not None:
        # 인덱스로 찾기
        if args.index < 0 or args.index >= len(sub_items):
            print(f"Error: Index {args.index} out of range", file=sys.stderr)
            sys.exit(1)
        sub_items[args.index]["done"] = True
        sub_items[args.index]["task_id"] = args.task_id
        idx = args.index
    elif args.match:
        # 제목 매칭으로 찾기
        found = False
        for i, item in enumerate(sub_items):
            if args.match.lower() in item.get("title", "").lower():
                sub_items[i]["done"] = True
                sub_items[i]["task_id"] = args.task_id
                idx = i
                found = True
                break
        if not found:
            print(f"Error: No sub_item matching '{args.match}'", file=sys.stderr)
            sys.exit(1)
    else:
        print("Error: Must specify --index or --match", file=sys.stderr)
        sys.exit(1)

    save_todo(data)
    print_json({"success": True, "index": idx}, pretty=not args.json)


def cmd_link(args: argparse.Namespace) -> None:
    """linked_tasks 추가."""
    data = load_todo()
    issue = find_issue(data, args.issue_id)

    if not issue:
        print(f"Error: Issue '{args.issue_id}' not found", file=sys.stderr)
        sys.exit(1)

    linked = issue.setdefault("linked_tasks", [])
    if args.task_id not in linked:
        linked.append(args.task_id)

    save_todo(data)
    print_json({"success": True, "linked_tasks": linked}, pretty=not args.json)


def main() -> None:
    parser = argparse.ArgumentParser(description="todo.json CRUD 관리")
    parser.add_argument("--json", action="store_true", help="JSON 한 줄 출력")
    subparsers = parser.add_subparsers(dest="command", required=True)

    # list
    p_list = subparsers.add_parser("list", help="이슈 목록")
    p_list.add_argument("--project", help="프로젝트 필터")
    p_list.add_argument("--status", help="상태 필터")
    p_list.set_defaults(func=cmd_list)

    # show
    p_show = subparsers.add_parser("show", help="이슈 상세")
    p_show.add_argument("issue_id", help="이슈 ID (예: issue-040)")
    p_show.set_defaults(func=cmd_show)

    # add
    p_add = subparsers.add_parser("add", help="이슈 추가")
    p_add.add_argument("--project", required=True, help="프로젝트명")
    p_add.add_argument("--title", required=True, help="제목")
    p_add.add_argument("--priority", choices=["high", "medium", "low", "normal"])
    p_add.add_argument("--status", choices=["pending", "in_progress", "done"])
    p_add.add_argument("--description", help="설명")
    p_add.set_defaults(func=cmd_add)

    # update
    p_upd = subparsers.add_parser("update", help="이슈 수정")
    p_upd.add_argument("issue_id")
    p_upd.add_argument("--status", choices=["pending", "in_progress", "done"])
    p_upd.add_argument("--priority", choices=["high", "medium", "low", "normal"])
    p_upd.add_argument("--title")
    p_upd.set_defaults(func=cmd_update)

    # remove
    p_rm = subparsers.add_parser("remove", help="이슈 삭제")
    p_rm.add_argument("issue_id")
    p_rm.add_argument("--force", "-f", action="store_true", help="확인 생략")
    p_rm.set_defaults(func=cmd_remove)

    # sub-add
    p_sa = subparsers.add_parser("sub-add", help="sub_item 추가")
    p_sa.add_argument("issue_id")
    p_sa.add_argument("--title", required=True)
    p_sa.set_defaults(func=cmd_sub_add)

    # sub-done
    p_sd = subparsers.add_parser("sub-done", help="sub_item 완료")
    p_sd.add_argument("issue_id")
    p_sd.add_argument("--index", type=int, help="인덱스 (0부터)")
    p_sd.add_argument("--match", help="제목 매칭 텍스트")
    p_sd.add_argument("--task-id", required=True, help="연결된 task ID")
    p_sd.set_defaults(func=cmd_sub_done)

    # link
    p_link = subparsers.add_parser("link", help="linked_tasks 추가")
    p_link.add_argument("issue_id")
    p_link.add_argument("task_id")
    p_link.set_defaults(func=cmd_link)

    args = parser.parse_args()
    args.func(args)


if __name__ == "__main__":
    main()
