from __future__ import annotations

from pathlib import Path

import pytest

from sync_state_machine.common.types import BindingStatus, SyncAction, SyncStatus
from sync_state_machine.engine import StateMachineConfig, StateMachineRuntime
from sync_state_machine.engine.events import e01_bootstrap
from sync_state_machine.sync_system.strategy_ops.reset_ops import _is_create_zombie
from tests.mocks.mock_datasource import MockSyncNode


CFG_PATH = Path(__file__).resolve().parents[2] / "sync_state_machine" / "config" / "node_state_machine.yaml"


def _new_node(*, node_id: str, action: SyncAction, status: SyncStatus, data_id: str) -> MockSyncNode:
    return MockSyncNode(
        node_id=node_id,
        data_id=data_id,
        data={"id": data_id or "", "name": "mock"},
        action=action,
        status=status,
        binding_status=BindingStatus.WARNING,
        error="seed-error",
    )


_CASES = [
    (action, status, data_id)
    for action in SyncAction
    for status in SyncStatus
    for data_id in ("", "id-1")
]


@pytest.mark.parametrize("action,status,data_id", _CASES)
def test_is_create_zombie_matrix(action: SyncAction, status: SyncStatus, data_id: str) -> None:
    node = _new_node(node_id=f"z-{action.value}-{status.value}-{data_id or 'empty'}", action=action, status=status, data_id=data_id)
    expected = action == SyncAction.CREATE and (status == SyncStatus.FAILED or not bool(data_id))
    assert _is_create_zombie(node) is expected


@pytest.mark.parametrize("action,status,data_id", _CASES)
def test_e01_bootstrap_accepts_all_combinations(action: SyncAction, status: SyncStatus, data_id: str) -> None:
    runtime = StateMachineRuntime(StateMachineConfig.load(CFG_PATH))
    node = _new_node(node_id=f"e01-{action.value}-{status.value}-{data_id or 'empty'}", action=action, status=status, data_id=data_id)

    original_action = node.action
    original_status = node.status
    original_binding = node.binding_status
    original_error = node.error

    is_zombie = _is_create_zombie(node)
    decision = e01_bootstrap(runtime, node=node, is_create_zombie=is_zombie)

    if is_zombie:
        assert decision.to_state == "S15"
        assert node.action == original_action
        assert node.status == original_status
        assert node.binding_status == original_binding
        assert node.error == original_error
    else:
        assert decision.to_state == "S00"
        assert node.binding_status == BindingStatus.UNCHECKED
        assert node.action == SyncAction.NONE
        assert node.status == SyncStatus.PENDING
        assert node.error is None
