"""provision 하기 전에 무엇이 일어날지 답한다.

위저드는 사용자에게 경로와 브랜치를 보여 준 뒤 확인을 받는다. 그 시점에 이미
worktree 를 만들어 버리면 안 되므로, 판단(재사용인가 신규인가, 어느 경로인가)만
떼어 여기에 둔다. 레지스트리를 읽기는 하지만 예약하지는 않는다 — 예약은
`provision` 의 몫이다.
"""
from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path

from .. import worktree_registry
from .git_ops import _is_inside_non_main_worktree, is_git_work_tree
from .naming import _safe_segment, compute_branch_name, compute_worktree_path


@dataclass
class WorktreeDecision:
    """Side-effect-free preview of what `provision_task_worktree` would do.

    status:
      - "new": no active registry entry; a fresh worktree would be created
      - "reused": registry already has this task-key; existing path/branch returned
      - "skipped-in-worktree": project_root is itself a non-main worktree
      - "skipped-not-git": project_root has no .git
    """
    status: str
    path: str              # worktree path (new: prospective; reuse: existing; skip: project_root)
    branch: str = ""       # new: prospective branch; reused: existing branch
    base_ref: str = ""     # new: requested base_ref; reused: existing base


def preview_worktree_decision(
    *,
    project_root,
    project_id: str,
    task_group_segment: str,
    task_id_segment: str,
    work_category: str,
    base_ref: str = "",
) -> "WorktreeDecision":
    """Side-effect-free: what provision_task_worktree WOULD do, without touching disk.

    Mirrors provision's decision branches exactly; reuses the same read-only
    helpers so preview never diverges from the actual provisioning result.
    """
    project_root = Path(project_root)
    if not is_git_work_tree(project_root):
        return WorktreeDecision(status="skipped-not-git", path=str(project_root))
    if _is_inside_non_main_worktree(project_root):
        return WorktreeDecision(status="skipped-in-worktree", path=str(project_root))
    safe_project = _safe_segment(project_id)
    safe_group = _safe_segment(task_group_segment)
    safe_task = _safe_segment(task_id_segment)
    existing = worktree_registry.lookup(safe_project, safe_group, safe_task)
    if existing is not None and existing.status == "active":
        return WorktreeDecision(
            status="reused", path=existing.worktree_path,
            branch=existing.branch, base_ref=existing.base_ref,
        )
    return WorktreeDecision(
        status="new",
        path=str(compute_worktree_path(
            project_id=safe_project, task_group_segment=safe_group,
            task_id_segment=safe_task)),
        branch=compute_branch_name(work_category=work_category, task_id_segment=safe_task),
        base_ref=base_ref,
    )


@dataclass
class StageWorktreeDecision:
    """Side-effect-free decision for one concrete implementation stage."""

    status: str
    path: str
    branch: str = ""
    base_ref: str = ""


def resolve_stage_worktree_decision(
    *,
    project_id: str,
    task_group_segment: str,
    task_id_segment: str,
    work_category: str,
    stage_number: int,
) -> StageWorktreeDecision:
    """Resolve whether one concrete stage worktree is new or reusable."""
    safe_project = _safe_segment(project_id)
    safe_group = _safe_segment(task_group_segment)
    safe_task = _safe_segment(task_id_segment)
    existing = worktree_registry.lookup(
        safe_project, safe_group, safe_task, stage_number=stage_number)
    if existing is not None and _stage_entry_is_reusable(existing):
        return StageWorktreeDecision(
            status="reused",
            path=existing.worktree_path,
            branch=existing.branch,
            base_ref=existing.base_ref,
        )
    return StageWorktreeDecision(
        status="new",
        path=str(compute_worktree_path(
            project_id=safe_project, task_group_segment=safe_group,
            task_id_segment=safe_task, stage_number=stage_number)),
        branch=compute_branch_name(
            work_category=work_category, task_id_segment=safe_task,
            stage_number=stage_number),
    )


def _stage_entry_is_reusable(entry: worktree_registry.WorktreeEntry) -> bool:
    """Whether a registered stage worktree can be entered by this run.

    `active` is the live-run case. `released` with the directory still on disk is
    the fix-run case: a stage whose verifier returned FAIL records a `failed`
    consumers row, which frees the occupancy but deliberately keeps the worktree
    and its branch as the reviewable stack. Re-entry MUST reuse that tree —
    provisioning anew refuses on the existing path and branch. After whole-task
    final-verification removes the directory the entry stops being reusable, so
    the stage provisions from scratch.
    """
    if entry.status == "active":
        return True
    return entry.status == "released" and Path(entry.worktree_path).is_dir()
