from __future__ import annotations

from sync_state_machine.common.types import BindingStatus, SyncStatus
from sync_state_machine.sync_system.strategy_ops.bind_ops import (
    check_dependency_satisfied,
    collect_dependency_errors,
)
from tests.fixtures.mock_domain import (
    TestProjectNode as ProjectNode,
)


def _normal_dep_node(*, data_id: str = "dep-1") -> ProjectNode:
    return ProjectNode(
        node_id="dep-node",
        data_id=data_id,
        data={"id": data_id or "", "name": "dep", "code": "DEP"},
        binding_status=BindingStatus.NORMAL,
        status=SyncStatus.PENDING,
    )


def test_check_dependency_satisfied_allows_empty_ref_by_default() -> None:
    ok = check_dependency_satisfied(
        dependency_nodes=[None],
        field_values=[""],
    )
    assert ok is True


def test_check_dependency_satisfied_blocks_empty_ref_when_strict() -> None:
    ok = check_dependency_satisfied(
        dependency_nodes=[None],
        field_values=[""],
        allow_empty_dependency_ref=False,
    )
    assert ok is False


def test_check_dependency_satisfied_missing_dep_data_id_strict_mode() -> None:
    node = _normal_dep_node(data_id="")
    loose = check_dependency_satisfied(
        dependency_nodes=[node],
        field_values=["P-1"],
        allow_missing_dep_data_id=True,
    )
    strict = check_dependency_satisfied(
        dependency_nodes=[node],
        field_values=["P-1"],
        allow_missing_dep_data_id=False,
    )
    assert loose is True
    assert strict is False


def test_collect_dependency_errors_covers_not_found_bad_status_and_no_data_id() -> None:
    bad_status_node = ProjectNode(
        node_id="dep-bad-status",
        data_id="dep-2",
        data={"id": "dep-2", "name": "dep2", "code": "DEP2"},
        binding_status=BindingStatus.WARNING,
        status=SyncStatus.PENDING,
    )
    no_data_id_node = ProjectNode(
        node_id="dep-no-id",
        data_id="",
        data={"id": "", "name": "dep3", "code": "DEP3"},
        binding_status=BindingStatus.NORMAL,
        status=SyncStatus.SUCCESS,
    )

    errors = collect_dependency_errors(
        dependency_nodes=[None, bad_status_node, no_data_id_node],
        field_names=["project_ref", "supplier_ref", "company_ref"],
        field_types=["project", "supplier", "company"],
        field_values=["P-404", "S-1", "C-1"],
        allow_empty_dependency_ref=False,
        allow_missing_dep_data_id=False,
    )

    assert errors == [
        "not_found|project_ref|project|P-404",
        "bad_status|supplier_ref|warning",
        "no_data_id|company_ref|status=SUCCESS",
    ]
