"""Helper script for resource_handler_crud.robot integration tests.

Exercises the read -> write -> diff cycle on a real temporary git
repository using GitCheckoutHandler, and on a real temporary directory
using FsDirectoryHandler.

Issue #827: ResourceHandler CRUD and discovery methods.
"""

from __future__ import annotations

import subprocess
import sys
import tempfile
from collections.abc import Callable
from pathlib import Path
from typing import NoReturn

_ROOT = Path(__file__).resolve().parents[1]
_SRC = str(_ROOT / "src")
# Ensure local source takes precedence over installed package.
# Remove any existing cleveragents modules so importlib re-resolves
# from sys.path[0] (our local src).
sys.path.insert(0, _SRC)
for _mod_name in list(sys.modules):
    if _mod_name.startswith("cleveragents"):
        del sys.modules[_mod_name]

from cleveragents.domain.models.core.resource import (  # noqa: E402
    PhysVirt,
    Resource,
    ResourceCapabilities,
)
from cleveragents.resource.handlers.fs_directory import FsDirectoryHandler  # noqa: E402
from cleveragents.resource.handlers.git_checkout import GitCheckoutHandler  # noqa: E402


def _fail(msg: str) -> NoReturn:
    print(msg, file=sys.stderr)
    sys.exit(1)


def _make_resource(rtype: str, location: str) -> Resource:
    return Resource(
        resource_id="01KJ5C5TPMP8GGX3QC83E2MAQS",
        resource_type_name=rtype,
        classification=PhysVirt.PHYSICAL,
        location=location,
        capabilities=ResourceCapabilities(
            readable=True, writable=True, sandboxable=True
        ),
    )


# ---------------------------------------------------------------------------
# fs-read-write-diff: FsDirectoryHandler read -> write -> diff cycle
# ---------------------------------------------------------------------------


def fs_read_write_diff() -> None:
    """Test read -> write -> diff cycle on FsDirectoryHandler."""
    handler = FsDirectoryHandler()

    # Create two temp dirs: source and comparison
    src = tempfile.mkdtemp(prefix="crud_robot_src_")
    cmp_dir = tempfile.mkdtemp(prefix="crud_robot_cmp_")

    # Write identical files to both
    Path(src, "file.txt").write_text("original\n", encoding="utf-8")
    Path(cmp_dir, "file.txt").write_text("original\n", encoding="utf-8")

    resource = _make_resource("fs-directory", src)

    # 1. Read
    content = handler.read(resource=resource, path="file.txt")
    if content.text.strip() != "original":
        _fail(f"read failed: expected 'original', got '{content.text.strip()}'")

    # 2. Write (modify)
    result = handler.write(resource=resource, path="file.txt", data=b"modified\n")
    if not result.success:
        _fail(f"write failed: {result.message}")

    # 3. Diff against comparison dir (should detect change)
    diff = handler.diff(resource=resource, other_location=cmp_dir)
    if not diff.has_changes:
        _fail("diff should detect changes after write")
    if diff.files_changed < 1:
        _fail(f"diff files_changed={diff.files_changed}, expected >= 1")

    # 4. List children
    children = handler.list_children(resource=resource)
    if "file.txt" not in children:
        _fail(f"list_children missing 'file.txt': {children}")

    print("fs-read-write-diff-ok")


# ---------------------------------------------------------------------------
# git-read-write-diff: GitCheckoutHandler read -> write -> diff cycle
# ---------------------------------------------------------------------------


def git_read_write_diff() -> None:
    """Test read -> write -> diff cycle on GitCheckoutHandler."""
    handler = GitCheckoutHandler()

    # Create a temp git repo
    repo = tempfile.mkdtemp(prefix="crud_robot_git_")
    subprocess.run(["git", "init"], cwd=repo, capture_output=True, check=True)
    subprocess.run(
        ["git", "config", "user.email", "test@test.com"],
        cwd=repo,
        capture_output=True,
        check=True,
    )
    subprocess.run(
        ["git", "config", "user.name", "Test"],
        cwd=repo,
        capture_output=True,
        check=True,
    )
    Path(repo, "code.py").write_text("print('hello')\n", encoding="utf-8")
    subprocess.run(["git", "add", "."], cwd=repo, capture_output=True, check=True)
    subprocess.run(
        ["git", "commit", "-m", "init"],
        cwd=repo,
        capture_output=True,
        check=True,
    )

    resource = _make_resource("git-checkout", repo)

    # Comparison dir
    cmp_dir = tempfile.mkdtemp(prefix="crud_robot_cmp_")
    Path(cmp_dir, "code.py").write_text("print('hello')\n", encoding="utf-8")

    # 1. Read
    content = handler.read(resource=resource, path="code.py")
    if "hello" not in content.text:
        _fail(f"read failed: 'hello' not in '{content.text}'")

    # 2. Write
    result = handler.write(resource=resource, path="code.py", data=b"print('world')\n")
    if not result.success:
        _fail(f"write failed: {result.message}")

    # 3. Diff (should detect change since we modified the file)
    diff = handler.diff(resource=resource, other_location=cmp_dir)
    if not diff.has_changes:
        _fail("diff should detect changes after write")

    # 4. List children
    children = handler.list_children(resource=resource)
    if "code.py" not in children:
        _fail(f"list_children missing 'code.py': {children}")

    # 5. Discover children (no subdirs expected)
    handler.discover_children(resource=resource)
    # May or may not have children — just ensure no crash

    print("git-read-write-diff-ok")


# ---------------------------------------------------------------------------
# Dispatcher
# ---------------------------------------------------------------------------

_COMMANDS: dict[str, Callable[[], None]] = {
    "fs-read-write-diff": fs_read_write_diff,
    "git-read-write-diff": git_read_write_diff,
}

if __name__ == "__main__":
    if len(sys.argv) < 2 or sys.argv[1] not in _COMMANDS:
        print(
            f"Usage: {sys.argv[0]} <{'|'.join(_COMMANDS)}>",
            file=sys.stderr,
        )
        sys.exit(1)
    _COMMANDS[sys.argv[1]]()
