"""`okstra wizard` CLI — argparse 와 서브커맨드 디스패치."""
from __future__ import annotations

import copy
import json
from pathlib import Path

from okstra_ctl.registry.host_registry import default_host_registry

from .state import WizardError
from .statefile import _save_resumed_state_file, load_state_file, save_state_file
from .confirmation import confirmation_block
from .engine import (
    _auto_start_new_task_when_it_is_the_only_choice,
    init_state,
    next_prompt,
    prompt_payload,
    submit,
)
from .render import render_args
from .outcome import wizard_outcome


# ---- CLI entrypoint -----------------------------------------------------

def main(argv: list[str]) -> int:
    """``python3 -m okstra_ctl.wizard <subcmd>`` driver.

    Subcommands:
      init  --state-file PATH --workspace-root P --project-root P --project-id ID
      step  --state-file PATH (--answer VALUE | --no-submit)
      render-args --state-file PATH
      confirmation --state-file PATH
      outcome --state-file PATH
    """
    import argparse

    parser = argparse.ArgumentParser(prog="okstra_ctl.wizard")
    sub = parser.add_subparsers(dest="cmd", required=True)

    p_init = sub.add_parser("init")
    p_init.add_argument("--state-file", required=True)
    p_init.add_argument("--workspace-root", required=True)
    p_init.add_argument("--project-root", required=True)
    p_init.add_argument("--project-id", required=True)
    p_init.add_argument("--preferred-task-key", default="")
    p_init.add_argument(
        "--host-runtime",
        default="claude-code",
        choices=default_host_registry().ids(),
    )
    p_init.add_argument(
        "--entry-mode",
        default="current-session",
        choices=("spawn-process", "current-session"),
    )
    p_init.add_argument("--available-function", action="append", default=[])
    p_init.add_argument("--critic", default="")

    p_step = sub.add_parser("step")
    p_step.add_argument("--state-file", required=True)
    p_step.add_argument("--answer", default=None)
    p_step.add_argument(
        "--no-submit",
        action="store_true",
        help="Fetch the current prompt without submitting an answer.",
    )

    p_render = sub.add_parser("render-args")
    p_render.add_argument("--state-file", required=True)

    p_conf = sub.add_parser("confirmation")
    p_conf.add_argument("--state-file", required=True)

    p_outcome = sub.add_parser("outcome")
    p_outcome.add_argument("--state-file", required=True)

    args = parser.parse_args(argv)
    state_path = Path(args.state_file)

    if args.cmd == "init":
        state = init_state(
            workspace_root=args.workspace_root,
            project_root=args.project_root,
            project_id=args.project_id,
            preferred_task_key=args.preferred_task_key,
            host_runtime=args.host_runtime,
            host_entry_mode=args.entry_mode,
            available_functions=args.available_function,
        )
        if args.critic:
            state.critic = args.critic
        _auto_start_new_task_when_it_is_the_only_choice(state)
        save_state_file(state_path, state)
        first = next_prompt(state)
        print(json.dumps({"ok": True, "next": prompt_payload(state, first)},
                         ensure_ascii=False, indent=2))
        return 0

    if args.cmd == "step":
        state = load_state_file(state_path)
        persisted_state = copy.deepcopy(state)
        if args.no_submit and args.answer is not None:
            print(json.dumps(
                {"ok": False, "error": "--no-submit and --answer are mutually exclusive"},
                ensure_ascii=False, indent=2,
            ))
            return 2
        if not args.no_submit and args.answer is None:
            print(json.dumps(
                {
                    "ok": False,
                    "error": (
                        "step requires --answer VALUE (use --answer '' to submit an "
                        "empty value, or --no-submit to peek at the current prompt)"
                    ),
                },
                ensure_ascii=False, indent=2,
            ))
            return 2
        try:
            if args.no_submit:
                result = {"echo": "", "next": prompt_payload(state, next_prompt(state))}
            else:
                result = submit(state, args.answer)
        except WizardError as exc:
            _save_resumed_state_file(state_path, persisted_state)
            try:
                # current 는 방금 디스크로 되돌린 상태에서 렌더한다. 뮤테이션이
                # 진행되다 만 state 로 렌더하면, 검증 전에 필드를 채운 핸들러
                # (예: reuse_previous)의 실패가 다음 스텝을 current 로 내보내
                # 재질문 계약("ok:false 면 같은 step 재제출")과 어긋난다.
                current = prompt_payload(
                    persisted_state, next_prompt(persisted_state)
                )
            except WizardError:
                # 현재 step 의 build 자체가 실패하면(예: 손상된 Stage Map 으로
                # _build_stage_pick·_build_handoff_stage_pick 가 raise) recovery 재렌더가
                # 같은 예외를 다시 던져 이중 실패한다 — try 밖이라 main 을 탈출해
                # traceback 으로 죽는다. current 를 비워 첫 예외를 깨끗한 envelope 로 낸다.
                current = None
            print(json.dumps({"ok": False, "error": str(exc), "current": current},
                             ensure_ascii=False, indent=2))
            return 0
        _save_resumed_state_file(state_path, state)
        print(json.dumps({"ok": True, **result}, ensure_ascii=False, indent=2))
        return 0

    if args.cmd == "render-args":
        state = load_state_file(state_path)
        try:
            rendered = render_args(state)
        except WizardError as exc:
            print(json.dumps({"ok": False, "error": str(exc)},
                             ensure_ascii=False, indent=2))
            return 0
        print(json.dumps({"ok": True, "args": rendered},
                         ensure_ascii=False, indent=2))
        return 0

    if args.cmd == "confirmation":
        state = load_state_file(state_path)
        print(json.dumps({"ok": True, "text": confirmation_block(state)},
                         ensure_ascii=False, indent=2))
        return 0

    if args.cmd == "outcome":
        state = load_state_file(state_path)
        try:
            out = wizard_outcome(state)
        except WizardError as exc:
            print(json.dumps({"ok": False, "error": str(exc)},
                             ensure_ascii=False, indent=2))
            return 0
        print(json.dumps({"ok": True, "outcome": out},
                         ensure_ascii=False, indent=2))
        return 0

    return 2
