"""Unit tests for ClientOperationState and acceptance parsing.

Author: Vasiliy Zdanovskiy
email: vasilyvz@gmail.com
"""

from __future__ import annotations

import pytest

from mcp_proxy_adapter.client.jsonrpc_client.operation_state import (
    build_operation_state_from_acceptance,
    parse_execution_acceptance,
    ClientOperationState,
)
from mcp_proxy_adapter.core.delivery.contracts import DeliveryMode
from mcp_proxy_adapter.core.delivery.exceptions import (
    ExecutionDeliveryIdentityCollisionError,
    InvalidDeliveryContractError,
)


def test_parse_valid_ws_with_status() -> None:
    raw = {
        "accepted": True,
        "job_id": "job-123",
        "ws_id": "ws-456",
        "delivery": {
            "mode": "ws_with_status",
            "terminal_only": True,
            "status_observable": True,
        },
    }
    payload = parse_execution_acceptance(raw)
    assert payload["accepted"] is True
    assert payload["job_id"] == "job-123"
    assert payload["ws_id"] == "ws-456"
    assert payload["delivery"].mode == DeliveryMode.WS_WITH_STATUS
    assert payload["delivery"].status_observable is True


def test_parse_rejects_ws_without_ws_id() -> None:
    raw = {
        "accepted": True,
        "job_id": "job-1",
        "ws_id": None,
        "delivery": {"mode": "ws", "terminal_only": True},
    }
    with pytest.raises(InvalidDeliveryContractError) as exc_info:
        parse_execution_acceptance(raw)
    assert (
        "ws_id" in str(exc_info.value).lower()
        or "required" in str(exc_info.value).lower()
    )


def test_build_initial_state() -> None:
    parsed = parse_execution_acceptance(
        {
            "accepted": True,
            "job_id": "job-123",
            "ws_id": "ws-456",
            "delivery": {
                "mode": "ws_with_status",
                "terminal_only": True,
                "status_observable": True,
            },
        }
    )
    state = build_operation_state_from_acceptance(parsed)
    assert state.job_id == "job-123"
    assert state.ws_id == "ws-456"
    assert state.delivery_mode == DeliveryMode.WS_WITH_STATUS
    assert state.delivery_status == "pending"
    assert state.execution_status is None


def test_apply_delivery_event_updates_terminal() -> None:
    state = ClientOperationState(
        job_id="job-1",
        ws_id="ws-1",
        delivery_mode=DeliveryMode.WS,
        execution_status=None,
        delivery_status="pending",
        result=None,
        error=None,
    )
    payload = {
        "event": "delivery_completed",
        "ws_id": "ws-1",
        "job_id": "job-1",
        "result": {"data": {"x": 1}},
        "error": None,
    }
    state.apply_delivery_event(payload)
    assert state.delivery_status == "delivery_completed"
    assert state.result == {"data": {"x": 1}}
    assert state.error is None


def test_apply_execution_status_ignores_ws_id() -> None:
    state = ClientOperationState(
        job_id="job-1",
        ws_id="ws-1",
        delivery_mode=DeliveryMode.WS_WITH_STATUS,
        execution_status=None,
        delivery_status="pending",
        result=None,
        error=None,
    )
    payload = {"status": "running", "ws_id": "stray-ws-id", "progress": 50}
    state.apply_execution_status(payload)
    assert state.execution_status == "running"
    assert state.ws_id == "ws-1"


def test_collision_on_mismatched_ws_id() -> None:
    state = ClientOperationState(
        job_id="job-1",
        ws_id="ws-1",
        delivery_mode=DeliveryMode.WS,
        execution_status=None,
        delivery_status="pending",
        result=None,
        error=None,
    )
    payload = {"event": "delivery_completed", "ws_id": "ws-other", "result": {}}
    with pytest.raises(ExecutionDeliveryIdentityCollisionError):
        state.apply_delivery_event(payload)
