"""Helper utilities for overlay sandbox Robot integration tests.

Covers the OverlaySandbox implementation: creation, path resolution,
commit, rollback, cleanup, and userspace fallback mode.
"""

from __future__ import annotations

import os
import sys
import tempfile

from cleveragents.infrastructure.sandbox.overlay import OverlaySandbox
from cleveragents.infrastructure.sandbox.protocol import (
    SandboxCreationError,
    SandboxStateError,
    SandboxStatus,
)


def _overlay_lifecycle() -> None:
    """Integration test: full overlay sandbox lifecycle."""
    tmpdir = tempfile.mkdtemp(prefix="ovl-robot-")
    original = os.path.join(tmpdir, "original")
    os.makedirs(original)

    with open(os.path.join(original, "readme.txt"), "w") as fh:
        fh.write("original readme")

    sandbox = OverlaySandbox(resource_id="robot-res", original_path=original)
    assert sandbox.status == SandboxStatus.PENDING
    assert sandbox.context is None

    ctx = sandbox.create("plan-robot-001")
    assert sandbox.status == SandboxStatus.CREATED
    assert ctx.plan_id == "plan-robot-001"
    assert ctx.metadata["strategy"] == "overlay"

    # Resolve path -> transitions to ACTIVE
    resolved = sandbox.get_path("readme.txt")
    assert sandbox.status == SandboxStatus.ACTIVE
    assert resolved.endswith("readme.txt")

    # Modify file in merged directory
    with open(resolved, "w") as fh:
        fh.write("modified readme")

    # Add a new file
    new_path = sandbox.get_path("new_file.txt")
    with open(new_path, "w") as fh:
        fh.write("new content")

    # Commit
    result = sandbox.commit()
    assert sandbox.status == SandboxStatus.COMMITTED
    assert result.success is True
    assert len(result.changed_files) == 1
    assert len(result.added_files) == 1
    assert len(result.deleted_files) == 0

    # Verify changes in original
    with open(os.path.join(original, "readme.txt")) as fh:
        assert fh.read() == "modified readme"
    with open(os.path.join(original, "new_file.txt")) as fh:
        assert fh.read() == "new content"

    # Cleanup
    sandbox.cleanup()
    assert sandbox.status == SandboxStatus.CLEANED_UP

    # Idempotent cleanup
    sandbox.cleanup()
    assert sandbox.status == SandboxStatus.CLEANED_UP

    print("overlay-lifecycle-ok")


def _overlay_rollback() -> None:
    """Integration test: overlay sandbox rollback."""
    tmpdir = tempfile.mkdtemp(prefix="ovl-robot-rb-")
    original = os.path.join(tmpdir, "original")
    os.makedirs(original)

    with open(os.path.join(original, "data.txt"), "w") as fh:
        fh.write("original data")

    sandbox = OverlaySandbox(resource_id="rb-res", original_path=original)
    sandbox.create("plan-robot-rb")

    # Make change and activate
    merged = sandbox.get_path("data.txt")
    with open(merged, "w") as fh:
        fh.write("modified data")

    # Rollback
    sandbox.rollback()
    assert sandbox.status == SandboxStatus.ROLLED_BACK

    # Verify merged directory is restored by directly checking
    # the merged dir (get_path not available in ROLLED_BACK state)
    assert sandbox._merged_dir is not None
    restored_path = os.path.join(sandbox._merged_dir, "data.txt")
    with open(restored_path) as fh:
        assert fh.read() == "original data"

    sandbox.cleanup()
    print("overlay-rollback-ok")


def _overlay_validation() -> None:
    """Integration test: overlay sandbox input validation."""
    # Empty resource_id
    try:
        OverlaySandbox(resource_id="", original_path="/tmp")
        print("FAIL: Expected ValueError for empty resource_id")
        return
    except ValueError:
        pass

    # Empty original_path
    try:
        OverlaySandbox(resource_id="res", original_path="")
        print("FAIL: Expected ValueError for empty original_path")
        return
    except ValueError:
        pass

    # Non-existent directory
    sandbox = OverlaySandbox(resource_id="res", original_path="/nonexistent/path")
    try:
        sandbox.create("plan-1")
        print("FAIL: Expected SandboxCreationError")
        return
    except SandboxCreationError:
        pass

    # Empty plan_id
    tmpdir = tempfile.mkdtemp(prefix="ovl-val-")
    os.makedirs(os.path.join(tmpdir, "orig"))
    sandbox2 = OverlaySandbox(
        resource_id="res", original_path=os.path.join(tmpdir, "orig")
    )
    try:
        sandbox2.create("")
        print("FAIL: Expected ValueError for empty plan_id")
        return
    except ValueError:
        pass

    print("overlay-validation-ok")


def _overlay_directory_structure() -> None:
    """Integration test: overlay sandbox creates correct structure."""
    tmpdir = tempfile.mkdtemp(prefix="ovl-robot-struct-")
    original = os.path.join(tmpdir, "original")
    os.makedirs(original)

    with open(os.path.join(original, "file.txt"), "w") as fh:
        fh.write("content")

    sandbox = OverlaySandbox(resource_id="struct-res", original_path=original)
    sandbox.create("plan-struct")

    assert sandbox._upper_dir is not None
    assert sandbox._work_dir is not None
    assert sandbox._merged_dir is not None
    assert os.path.isdir(sandbox._upper_dir)
    assert os.path.isdir(sandbox._work_dir)
    assert os.path.isdir(sandbox._merged_dir)

    # Merged should contain original files
    assert os.path.isfile(os.path.join(sandbox._merged_dir, "file.txt"))

    sandbox.cleanup()
    print("overlay-directory-structure-ok")


def _overlay_fallback_mode() -> None:
    """Integration test: overlay sandbox uses userspace fallback."""
    tmpdir = tempfile.mkdtemp(prefix="ovl-robot-fb-")
    original = os.path.join(tmpdir, "original")
    os.makedirs(original)

    sandbox = OverlaySandbox(resource_id="fb-res", original_path=original)
    # In CI/containers, OverlayFS is typically not available
    assert sandbox._use_real_overlay is False

    sandbox.create("plan-fb")
    sandbox.cleanup()
    print("overlay-fallback-mode-ok")


def _overlay_state_errors() -> None:
    """Integration test: overlay sandbox state errors."""
    tmpdir = tempfile.mkdtemp(prefix="ovl-robot-se-")
    original = os.path.join(tmpdir, "original")
    os.makedirs(original)

    sandbox = OverlaySandbox(resource_id="se-res", original_path=original)
    sandbox.create("plan-se")

    # Rollback from CREATED should raise
    try:
        sandbox.rollback()
        print("FAIL: Expected SandboxStateError for rollback from CREATED")
        return
    except SandboxStateError:
        pass

    # Commit then attempt commit again
    sandbox.commit()
    try:
        sandbox.commit()
        print("FAIL: Expected SandboxStateError for double commit")
        return
    except SandboxStateError:
        pass

    sandbox.cleanup()

    # Get path on cleaned up sandbox should raise
    try:
        sandbox.get_path("file.txt")
        print("FAIL: Expected SandboxStateError for get_path after cleanup")
        return
    except SandboxStateError:
        pass

    print("overlay-state-errors-ok")


_COMMANDS = {
    "overlay-lifecycle": _overlay_lifecycle,
    "overlay-rollback": _overlay_rollback,
    "overlay-validation": _overlay_validation,
    "overlay-directory-structure": _overlay_directory_structure,
    "overlay-fallback-mode": _overlay_fallback_mode,
    "overlay-state-errors": _overlay_state_errors,
}


def main() -> None:
    """Entry point for Robot helper."""
    if len(sys.argv) < 2 or sys.argv[1] not in _COMMANDS:
        valid = "|".join(sorted(_COMMANDS))
        print(f"Usage: {sys.argv[0]} <{valid}>")
        sys.exit(1)

    _COMMANDS[sys.argv[1]]()


if __name__ == "__main__":
    main()
