"""Step definitions for TOCTOU race condition fix in git worktree sandbox.

All steps use the ``gwt toctou`` prefix to avoid collisions with the
existing ``gwt`` steps in ``git_worktree_sandbox_steps.py``.
"""

from __future__ import annotations

import os

from behave import then, when
from behave.runner import Context


def _ensure_saved_sandboxes(ctx: Context) -> dict[str, object]:
    """Return the saved-sandboxes dict, creating it if absent."""
    if not hasattr(ctx, "gwt_toctou_saved"):
        ctx.gwt_toctou_saved: dict[str, object] = {}
    return ctx.gwt_toctou_saved  # type: ignore[no-any-return]


# ---------------------------------------------------------------------------
# When — save / record helpers
# ---------------------------------------------------------------------------


@when('the gwt toctou sandbox is saved as "{label}"')
def step_gwt_toctou_save(ctx: Context, label: str) -> None:
    saved = _ensure_saved_sandboxes(ctx)
    saved[label] = ctx.gwt_sandbox


@when("the gwt toctou parent directory path is recorded")
def step_gwt_toctou_record_parent(ctx: Context) -> None:
    parent = getattr(ctx.gwt_sandbox, "_parent_temp_dir", None)
    assert parent is not None, "Sandbox has no _parent_temp_dir attribute"
    ctx.gwt_toctou_parent_path: str = parent


# ---------------------------------------------------------------------------
# Then — parent directory assertions
# ---------------------------------------------------------------------------


@then("the gwt toctou sandbox should have a parent temp directory")
def step_gwt_toctou_has_parent(ctx: Context) -> None:
    parent = getattr(ctx.gwt_sandbox, "_parent_temp_dir", None)
    assert parent is not None, "Expected _parent_temp_dir to be set"
    assert os.path.isdir(parent), f"Parent temp dir does not exist: {parent}"


@then("the gwt toctou worktree should be a subdirectory of its parent")
def step_gwt_toctou_worktree_is_child(ctx: Context) -> None:
    parent = ctx.gwt_sandbox._parent_temp_dir
    worktree = ctx.gwt_sandbox.context.sandbox_path
    assert worktree.startswith(parent + os.sep), (
        f"Worktree {worktree} is not under parent {parent}"
    )


@then("the gwt toctou recorded parent directory should not exist")
def step_gwt_toctou_parent_gone(ctx: Context) -> None:
    parent = ctx.gwt_toctou_parent_path
    assert not os.path.exists(parent), (
        f"Parent directory should have been removed: {parent}"
    )


# ---------------------------------------------------------------------------
# Then — saved-sandbox assertions
# ---------------------------------------------------------------------------


@then('the gwt toctou saved sandbox "{label}" worktree path should exist')
def step_gwt_toctou_saved_exists(ctx: Context, label: str) -> None:
    saved = _ensure_saved_sandboxes(ctx)
    sandbox = saved[label]
    assert sandbox.context is not None
    assert os.path.isdir(sandbox.context.sandbox_path), (
        f"Worktree for '{label}' does not exist"
    )


@then('the gwt toctou saved sandbox paths "{a}" and "{b}" should differ')
def step_gwt_toctou_saved_differ(ctx: Context, a: str, b: str) -> None:
    saved = _ensure_saved_sandboxes(ctx)
    path_a = saved[a].context.sandbox_path
    path_b = saved[b].context.sandbox_path
    assert path_a != path_b, f"Paths should differ but both are {path_a}"
