"""task-key → (task_root, project_root) 해석 공유 헬퍼.

read-side CLI(context-cost, error-report)가 동일한 입력 계약을 공유하기 위한
SSOT. target 은 task-root 경로 / task-key 둘 다 받는다.
"""
from __future__ import annotations

from pathlib import Path

from okstra_project import (
    ResolverError,
    StateError,
    find_task_root,
    resolve_project_root,
)


def resolve_task_root(target: str, project_root: str, cwd: str) -> tuple[Path, Path]:
    target_path = Path(target).expanduser()
    if target_path.exists():
        task_root = target_path.resolve()
        return task_root, infer_project_root(task_root)

    try:
        resolved_project = Path(
            resolve_project_root(explicit_root=project_root, cwd=cwd)
        ).resolve()
    except ResolverError as exc:
        raise SystemExit(f"project root resolution failed: {exc}") from exc

    try:
        task_root = find_task_root(resolved_project, target)
    except StateError as exc:
        raise SystemExit(
            f"target is neither an existing path nor a valid task-key: "
            f"{target!r} ({exc})"
        ) from exc
    if task_root is None:
        raise SystemExit(f"no task root for task key: {target}")
    return task_root.resolve(), resolved_project


def infer_project_root(task_root: Path) -> Path:
    parts = task_root.parts
    if ".okstra" not in parts:
        return task_root
    # The okstra subtree (.okstra/tasks/...) introduces the deepest ".okstra"
    # segment; a project checked out under a path that itself contains
    # ".okstra" must not resolve to that outer segment.
    idx = len(parts) - 1 - parts[::-1].index(".okstra")
    return Path(*parts[:idx]).resolve()


def project_rel(path: Path, project_root: Path) -> str:
    try:
        return str(path.resolve().relative_to(project_root.resolve()))
    except ValueError:
        return str(path)
