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

Each subcommand is a self-contained check that prints a sentinel on success.
"""

from __future__ import annotations

import sys
from pathlib import Path

# Ensure local source tree is importable
_SRC = str(Path(__file__).resolve().parents[1] / "src")
if _SRC not in sys.path:
    sys.path.insert(0, _SRC)

from cleveragents.a2a.facade import A2aLocalFacade  # noqa: E402
from cleveragents.a2a.models import A2aRequest  # noqa: E402
from cleveragents.a2a.sync_models import (  # noqa: E402
    ConflictResolution,
    SyncDirection,
    SyncEntitySnapshot,
    SyncEntityType,
    SyncOperationStatus,
    SyncPullRequest,
    VectorClock,
)
from cleveragents.application.services.sync_service import SyncService  # noqa: E402

# ---------------------------------------------------------------------------
# Subcommands
# ---------------------------------------------------------------------------


def sync_pull() -> None:
    """Test sync pull via facade."""
    svc = SyncService(node_id="robot-client")
    entity = SyncEntitySnapshot(
        entity_id="robot-actor",
        entity_type=SyncEntityType.ACTOR,
        namespace="team",
        name="robot-actor",
        vector_clock=VectorClock(entries={"server": 1}),
    )
    svc.register_server_entity(entity)

    facade = A2aLocalFacade(services={"sync_service": svc})
    request = A2aRequest(
        method="_cleveragents/sync/pull",
        params={"namespace": "team"},
    )
    response = facade.dispatch(request)
    result = response.result or {}
    if response.error is None and result.get("total_pulled", 0) >= 1:
        print("sync-pull-ok")
    else:
        print(f"FAIL: {response.error or result}", file=sys.stderr)
        sys.exit(1)


def sync_push() -> None:
    """Test sync push via facade."""
    svc = SyncService(node_id="robot-client")
    facade = A2aLocalFacade(services={"sync_service": svc})

    params = {
        "namespace": "team",
        "entities": [
            {
                "entity_id": "push-actor",
                "entity_type": "actor",
                "namespace": "team",
                "name": "push-test",
            },
        ],
    }
    request = A2aRequest(
        method="_cleveragents/sync/push",
        params=params,
    )
    response = facade.dispatch(request)
    result = response.result or {}
    if response.error is None and result.get("total_accepted", 0) >= 1:
        print("sync-push-ok")
    else:
        print(f"FAIL: {response.error or result}", file=sys.stderr)
        sys.exit(1)


def sync_status() -> None:
    """Test sync status via facade."""
    svc = SyncService(node_id="robot-client")
    entity = SyncEntitySnapshot(
        entity_id="status-actor",
        entity_type=SyncEntityType.ACTOR,
        namespace="team",
        name="status-actor",
        vector_clock=VectorClock(entries={"client": 1}),
    )
    svc.register_local_entity(entity)

    facade = A2aLocalFacade(services={"sync_service": svc})
    request = A2aRequest(
        method="_cleveragents/sync/status",
        params={"namespace": "team"},
    )
    response = facade.dispatch(request)
    result = response.result or {}
    if response.error is None and result.get("drift_detected") is True:
        print("sync-status-ok")
    else:
        print(f"FAIL: {response.error or result}", file=sys.stderr)
        sys.exit(1)


def sync_conflict_resolution() -> None:
    """Test conflict detection and resolution."""
    svc = SyncService(node_id="robot-client")

    local_ent = SyncEntitySnapshot(
        entity_id="conflict-actor",
        entity_type=SyncEntityType.ACTOR,
        namespace="team",
        name="conflict-actor",
        vector_clock=VectorClock(entries={"client": 2, "server": 1}),
        updated_at="2025-06-01T12:00:00+00:00",
    )
    server_ent = SyncEntitySnapshot(
        entity_id="conflict-actor",
        entity_type=SyncEntityType.ACTOR,
        namespace="team",
        name="conflict-actor",
        vector_clock=VectorClock(entries={"client": 1, "server": 2}),
        updated_at="2025-05-01T12:00:00+00:00",
    )
    svc.register_local_entity(local_ent)
    svc.register_server_entity(server_ent)

    pull_req = SyncPullRequest(namespace="team")
    pull_resp = svc.pull(pull_req)
    if len(pull_resp.conflicts) != 1:
        print(
            f"FAIL: expected 1 conflict, got {len(pull_resp.conflicts)}",
            file=sys.stderr,
        )
        sys.exit(1)

    conflict_id = svc.conflicts[0].conflict_id
    resolved = svc.resolve_conflict(
        conflict_id=conflict_id,
        resolution=ConflictResolution.LAST_WRITER_WINS,
    )
    if resolved.resolved and resolved.winner == "local":
        print("sync-conflict-resolution-ok")
    else:
        print(
            f"FAIL: resolved={resolved.resolved}, winner={resolved.winner}",
            file=sys.stderr,
        )
        sys.exit(1)


def sync_offline_queue() -> None:
    """Test offline queue operations."""
    svc = SyncService(node_id="robot-client")
    entity = SyncEntitySnapshot(
        entity_id="offline-actor",
        entity_type=SyncEntityType.ACTOR,
        namespace="team",
        name="offline-actor",
        vector_clock=VectorClock(entries={"client": 1}),
    )
    entry = svc.enqueue_offline(
        direction=SyncDirection.PUSH,
        namespace="team",
        entity=entity,
    )
    if entry.status != SyncOperationStatus.QUEUED:
        print(f"FAIL: expected QUEUED, got {entry.status}", file=sys.stderr)
        sys.exit(1)

    processed = svc.process_offline_queue()
    if len(processed) >= 1 and len(svc.offline_queue) == 0:
        print("sync-offline-queue-ok")
    else:
        print(
            f"FAIL: processed={len(processed)}, remaining={len(svc.offline_queue)}",
            file=sys.stderr,
        )
        sys.exit(1)


def sync_vector_clock() -> None:
    """Test vector clock operations."""
    c1 = VectorClock(entries={"a": 1, "b": 2})
    c2 = VectorClock(entries={"a": 2, "b": 3})

    if not c1.happens_before(c2):
        print("FAIL: c1 should happen before c2", file=sys.stderr)
        sys.exit(1)

    c3 = VectorClock(entries={"a": 2, "b": 1})
    if not c1.is_concurrent(c3):
        print("FAIL: c1 and c3 should be concurrent", file=sys.stderr)
        sys.exit(1)

    merged = c1.merge(c2)
    if merged.entries != {"a": 2, "b": 3}:
        print(f"FAIL: unexpected merge result {merged.entries}", file=sys.stderr)
        sys.exit(1)

    incremented = c1.increment("a")
    if incremented.entries["a"] != 2:
        print(f"FAIL: expected a=2, got {incremented.entries['a']}", file=sys.stderr)
        sys.exit(1)

    print("sync-vector-clock-ok")


def sync_facade_no_service() -> None:
    """Test facade sync stubs when no service is registered."""
    facade = A2aLocalFacade()
    for op in (
        "_cleveragents/sync/pull",
        "_cleveragents/sync/push",
        "_cleveragents/sync/status",
    ):
        request = A2aRequest(method=op, params={"namespace": "test"})
        response = facade.dispatch(request)
        result = response.result or {}
        if response.error is not None or not result.get("stub"):
            print(
                f"FAIL: {op} should return stub, got {response.error or result}",
                file=sys.stderr,
            )
            sys.exit(1)
    print("sync-facade-no-service-ok")


def sync_incremental() -> None:
    """Test incremental sync with since parameter."""
    svc = SyncService(node_id="robot-client")
    old_entity = SyncEntitySnapshot(
        entity_id="old-actor",
        entity_type=SyncEntityType.ACTOR,
        namespace="team",
        name="old-actor",
        vector_clock=VectorClock(entries={"server": 1}),
        updated_at="2024-01-01T00:00:00+00:00",
    )
    new_entity = SyncEntitySnapshot(
        entity_id="new-actor",
        entity_type=SyncEntityType.ACTOR,
        namespace="team",
        name="new-actor",
        vector_clock=VectorClock(entries={"server": 2}),
        updated_at="2025-06-01T00:00:00+00:00",
    )
    svc.register_server_entity(old_entity)
    svc.register_server_entity(new_entity)

    pull_req = SyncPullRequest(
        namespace="team",
        since="2025-01-01T00:00:00+00:00",
    )
    resp = svc.pull(pull_req)
    if resp.total_pulled == 1 and resp.entities[0].entity_id == "new-actor":
        print("sync-incremental-ok")
    else:
        print(f"FAIL: expected 1 entity, got {resp.total_pulled}", file=sys.stderr)
        sys.exit(1)


# ---------------------------------------------------------------------------
# CLI dispatch
# ---------------------------------------------------------------------------

_COMMANDS: dict[str, object] = {
    "sync-pull": sync_pull,
    "sync-push": sync_push,
    "sync-status": sync_status,
    "sync-conflict-resolution": sync_conflict_resolution,
    "sync-offline-queue": sync_offline_queue,
    "sync-vector-clock": sync_vector_clock,
    "sync-facade-no-service": sync_facade_no_service,
    "sync-incremental": sync_incremental,
}

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