"""Shared test-infra helpers for pointing engine paths at pytest tmp dirs.

REC-18: the pipeline path SSOT (`recoil/core/paths.py`) carries two
production guards that pytest tmp roots don't satisfy out of the box:

  1. `_assert_data_root` requires a `.recoil-data-root` sentinel file in the
     resolved projects root (Law 4: fail loud if Dropbox/Smart-Sync stubbed
     out the data tree). The real `~/Dropbox/CLAUDE_DATA/recoil/projects`
     carries this file; a bare pytest `tmp_path` does not.
  2. `ProjectPaths.for_project` raises `FileNotFoundError` for project slugs
     whose directory does not exist on disk. The real data tree has a
     directory per project; tests that point at an empty tmp root do not.

Both guards stay ACTIVE in production. These helpers ONLY make a test's tmp
projects-root look like the real data root, and ONLY for roots that live
under pytest's session basetemp. Any production-shaped root flows through the
real guards unchanged — the Law-4 assertion itself is never patched or
weakened.

Used by the autouse `recoil_data_root_sentinel` fixture in this directory's
conftest.py and the orchestrator tests' conftest.py.
"""

from __future__ import annotations

import sys
import pathlib

# Bootstrap import roots before touching any recoil.* symbol — mirrors the
# per-file bootstrap each test module performs at import time.
sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent.parent.parent.parent))
from recoil.core import paths as _paths  # noqa: E402

SENTINEL_NAME = ".recoil-data-root"

# pytest session basetemp — the ONLY directory tree under which these shims
# fabricate sentinels / project dirs. Set once per session by the fixture.
_basetemp: pathlib.Path | None = None


def set_basetemp(path) -> None:
    global _basetemp
    _basetemp = pathlib.Path(path).resolve()


def _under_basetemp(root: pathlib.Path) -> bool:
    if _basetemp is None:
        return False
    root = root.resolve()
    return root == _basetemp or _basetemp in root.parents


# ── projects_root shim: ensure the sentinel for tmp roots ────────────────

_orig_projects_root = _paths.projects_root


def _patched_projects_root() -> pathlib.Path:
    """If RECOIL_PROJECTS_ROOT points under pytest's basetemp, make sure the
    root + sentinel exist before delegating. Mirrors the real data root."""
    import os

    override = os.environ.get("RECOIL_PROJECTS_ROOT", "").strip()
    if override:
        candidate = pathlib.Path(override).expanduser()
        if _under_basetemp(candidate.resolve() if candidate.exists() else candidate):
            candidate.mkdir(parents=True, exist_ok=True)
            (candidate / SENTINEL_NAME).touch()
    return _orig_projects_root()


# ── for_project shim: auto-create project dirs under tmp roots ──────────

_orig_for_project = _paths.ProjectPaths.for_project.__func__


def _patched_for_project(cls, project=None):
    """Auto-create the project dir when the resolved projects root is under
    pytest's basetemp. Outside the basetemp this is a transparent
    pass-through to the production implementation."""
    try:
        root = _paths.projects_root()
    except _paths.ProjectsRootUnresolvable:
        return _orig_for_project(cls, project)
    if _under_basetemp(root):
        default = _paths.get_pipeline_config().get("default_project", "leviathan")
        proj = (project or default).lower()
        (root / proj).mkdir(parents=True, exist_ok=True)
    return _orig_for_project(cls, project)


def install_shims() -> None:
    """Idempotently install the projects_root + for_project test shims."""
    if _paths.projects_root is not _patched_projects_root:
        _paths.projects_root = _patched_projects_root
    if (
        getattr(_paths.ProjectPaths.for_project, "__func__", None)
        is not _patched_for_project
    ):
        _paths.ProjectPaths.for_project = classmethod(_patched_for_project)
