"""프로젝트 루트 해석·project.json upsert·PR 템플릿 해석의 CLI 경계.

이 네 갈래는 원래 `config.mts` · `setup.mts` · `check-project.mts` 안에
파이썬 소스 배열로 각각 복사돼 있었다(docs/coding-rules.md R1 위반, 그리고
같은 해석을 네 벌 유지하는 중복). 로직은 그대로 옮겼고 출력 형식도 그대로다 —
호출부의 파서를 건드리지 않기 위해서다.
"""
from __future__ import annotations

import argparse
import json
import sys
from pathlib import Path

from okstra_project import (
    ResolverError,
    project_json_path,
    resolve_project_root,
    upsert_project_json,
)

from .json_boundary import JsonBoundaryError, load_owned_object


def _resolve(args: argparse.Namespace) -> int:
    """`PROJECT_ROOT` / `PROJECT_JSON` 또는 `RESOLVER_ERROR` 태그 줄."""
    try:
        pr = resolve_project_root(explicit_root=args.explicit_root, cwd=args.cwd)
    except ResolverError as exc:
        print("RESOLVER_ERROR", exc)
        return 0
    print("PROJECT_ROOT", pr)
    print("PROJECT_JSON", project_json_path(pr))
    return 0


def _resolve_root(args: argparse.Namespace) -> int:
    """루트 경로만 stdout 으로.

    `--on-error` 로 실패 취급이 갈린다. `fail` 은 stderr + 비0(엄격한 호출부),
    `empty` 는 아무것도 내지 않고 0(autofill 처럼 실패해도 진행하는 호출부).
    두 갈래를 한 구현 안에 두는 이유는, 예전에 셸과 TS 가 같은 해석을 각자
    베껴 두어 갈라질 수 있었기 때문이다.
    """
    try:
        root = resolve_project_root(explicit_root=args.explicit_root, cwd=args.cwd)
    except ResolverError as exc:
        if args.on_error == "fail":
            sys.stderr.write(f"{args.error_prefix}{exc}\n")
            return args.error_code
        return 0
    print(root)
    return 0


def _upsert(args: argparse.Namespace) -> int:
    """`--format tagged` 는 `OK <json>` / `ERROR <msg>`, `strict` 는 stderr + 비0."""
    try:
        result = upsert_project_json(Path(args.project_root), args.project_id)
    except ResolverError as exc:
        if args.format == "strict":
            sys.stderr.write(f"project.json upsert failed: {exc}\n")
            return 1
        print("ERROR", exc)
        return 0
    if args.format == "tagged":
        print("OK", json.dumps(result))
    return 0


def _project_json(args: argparse.Namespace) -> int:
    """`<projectId>\t<projectRoot>` 한 줄. 해석·파일 어느 쪽이든 없으면 아무것도 내지 않는다."""
    try:
        root = resolve_project_root(explicit_root=args.explicit_root or "")
    except ResolverError:
        return 0
    path = project_json_path(Path(root))
    if not path.is_file():
        return 0
    try:
        data = load_owned_object(path, artifact="project.json")
    except JsonBoundaryError:
        # 깨진 project.json 은 autofill 을 끄는 신호다 — 이 경로의 호출부는
        # 값을 못 얻으면 사용자에게 직접 묻는다. 여기서 죽이면 물어볼 기회도 없다.
        return 0
    print(f"{data.get('projectId', '')}\t{root}")
    return 0


def _pr_template(args: argparse.Namespace) -> int:
    from .pr_template import PrTemplateError, resolve_pr_template_path

    try:
        resolved = resolve_pr_template_path(Path(args.project_root))
    except PrTemplateError as exc:
        print(json.dumps({"ok": False, "reason": str(exc)}))
        return 0
    print(json.dumps({
        "ok": True, "path": str(resolved.path), "source": resolved.source,
    }))
    return 0


def main(argv: list[str] | None = None) -> int:
    parser = argparse.ArgumentParser(prog="okstra project-setup")
    sub = parser.add_subparsers(dest="op", required=True)

    resolve = sub.add_parser("resolve")
    resolve.add_argument("--explicit-root", default="")
    resolve.add_argument("--cwd", required=True)
    resolve.set_defaults(handler=_resolve)

    resolve_root = sub.add_parser("resolve-root")
    resolve_root.add_argument("--explicit-root", default="")
    resolve_root.add_argument("--cwd", default="")
    resolve_root.add_argument("--on-error", choices=("fail", "empty"), default="fail")
    resolve_root.add_argument("--error-prefix", default="")
    resolve_root.add_argument("--error-code", type=int, default=2)
    resolve_root.set_defaults(handler=_resolve_root)

    upsert = sub.add_parser("upsert")
    upsert.add_argument("--project-root", required=True)
    upsert.add_argument("--project-id", required=True)
    upsert.add_argument("--format", choices=("tagged", "strict"), default="tagged")
    upsert.set_defaults(handler=_upsert)

    project_json = sub.add_parser("project-json")
    project_json.add_argument("--explicit-root", default="")
    project_json.set_defaults(handler=_project_json)

    pr_template = sub.add_parser("pr-template")
    pr_template.add_argument("--project-root", required=True)
    pr_template.set_defaults(handler=_pr_template)

    args = parser.parse_args(argv)
    return args.handler(args)


if __name__ == "__main__":
    raise SystemExit(main())
