"""invocation JSON 경로/저장/로드."""
from __future__ import annotations

import json
import os
from pathlib import Path
from typing import Optional

from .ids import _safe_fs_segment
from .json_boundary import load_owned_object, write_owned_object_atomic


def invocation_path(home: Path, project_id: str,
                    task_group: str, task_id: str, task_type: str,
                    run_seq: int) -> Path:
    """invocation JSON 파일 절대경로.
    okstra 의 run_seq 는 (group, task_id, task_type) 별로 독립이므로 같은 project 안에
    seq=1 인 run 이 여러 개일 수 있다. 따라서 파일명은 4-tuple 전체로 유일성을 보장한다.
    """
    seq = f"{run_seq:02d}" if run_seq < 100 else str(run_seq)
    # 세그먼트를 평탄 조인하면 ('feature-8','email') 과 ('feature','8-email')
    # 가 같은 파일로 충돌하므로, 각 세그먼트를 하위 디렉터리로 분리해 경계
    # 정보를 손실 없이 보존한다. 또한 task_group/task_id 등은 CLI/manifest
    # 에서 들어오는 미검증 값이므로 fs-safe 슬러그로 강제 정규화해 `/` 나
    # `..` 가 invocations 디렉터리 밖으로 path 를 escape 시키는 것을 막는다.
    return (home / "projects" / _safe_fs_segment(project_id) / "invocations"
            / _safe_fs_segment(task_group) / _safe_fs_segment(task_id)
            / _safe_fs_segment(task_type) / f"r{seq}.json")


def save_invocation(home: Path, project_id: str,
                    task_group: str, task_id: str, task_type: str,
                    run_seq: int, payload: dict) -> None:
    """invocation 을 원자적으로 저장(임시파일 + os.replace)."""
    target = invocation_path(home, project_id, task_group, task_id, task_type, run_seq)
    write_owned_object_atomic(target, payload, artifact="invocation metadata")


def load_invocation(home: Path, project_id: str,
                    task_group: str, task_id: str, task_type: str,
                    run_seq: int) -> Optional[dict]:
    """invocation JSON 을 읽는다. 없으면 None."""
    target = invocation_path(home, project_id, task_group, task_id, task_type, run_seq)
    if not target.is_file():
        return None
    return load_owned_object(target, artifact="invocation metadata")
