"""Filesystem locations for agent session transcripts and time helpers."""
from __future__ import annotations

import os
from datetime import datetime, timezone
from pathlib import Path
from typing import Mapping


HOME = Path.home()
CLAUDE_PROJECTS = HOME / ".claude" / "projects"
CODEX_SESSIONS = HOME / ".agent" / "sessions"


def codex_session_roots(
    home: Path,
    env: Mapping[str, str],
) -> tuple[Path, ...]:
    """Return Codex transcript roots in configuration precedence order."""
    candidates: list[Path] = []
    configured_home = env.get("CODEX_HOME", "").strip()
    if configured_home:
        candidates.append(Path(configured_home).expanduser() / "sessions")
    candidates.extend((
        home / ".codex" / "sessions",
        home / ".agent" / "sessions",
    ))

    roots: list[Path] = []
    seen: set[Path] = set()
    for candidate in candidates:
        normalized = Path(os.path.abspath(candidate))
        if normalized in seen:
            continue
        seen.add(normalized)
        roots.append(candidate)
    return tuple(roots)


def utc_now() -> str:
    return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")


def _floor_to_second(ts: str) -> datetime | None:
    try:
        moment = datetime.fromisoformat(ts.replace("Z", "+00:00"))
    except ValueError:
        return None
    if moment.tzinfo is None:
        moment = moment.replace(tzinfo=timezone.utc)
    return moment.replace(microsecond=0)


def ts_in_window(ts: str, since: str | None, until: str | None) -> bool:
    """ts 가 run 윈도우 [since, until] 안인지 — 초 단위로 절삭해 비교한다.

    세션 jsonl 의 ts 는 밀리초(`…00.123Z`), 윈도우 끝점(run-manifest createdAt /
    status mtime)은 초(`…00Z`) 정밀도라 문자열 비교는 '.' < 'Z' 탓에 경계 초의
    레코드를 잘못 떨군다. 파싱 불가한 끝점은 개방 경계로, 파싱 불가한 ts 는
    포함으로 취급한다(빈 ts 를 포함시키는 기존 동작과 동일 원칙).
    """
    moment = _floor_to_second(ts)
    if moment is None:
        return True
    lo = _floor_to_second(since) if since else None
    hi = _floor_to_second(until) if until else None
    return not ((lo is not None and moment < lo) or (hi is not None and moment > hi))


def claude_project_dir(cwd: Path, projects_root: Path | None = None) -> Path:
    # Claude Code encodes cwd by replacing "/" with "-" (leading slash → leading "-").
    # `projects_root` 는 테스트/진단용 주입 시드 — 기본은 실제 ~/.claude/projects.
    encoded = "-" + str(cwd).strip("/").replace("/", "-")
    return (projects_root or CLAUDE_PROJECTS) / encoded
