from __future__ import annotations

import logging
from pathlib import Path

import pytest

from sync_state_machine.common.binding import BindingManager
from sync_state_machine.common.collection import DataCollection
from sync_state_machine.common.persistence import PersistenceBackend
from sync_state_machine.common.sqlite_backend import SQLitePersistenceBackend
from sync_state_machine.common.types import BindingStatus, SyncAction, SyncStatus
from sync_state_machine.domain.construction.sync_node import ConstructionTaskSyncNode
from sync_state_machine.domain.construction.sync_strategy import ConstructionTaskSyncStrategy
from sync_state_machine.domain.contract.sync_node import ContractSyncNode
from sync_state_machine.domain.contract.sync_strategy import ContractSyncStrategy
from sync_state_machine.sync_system.strategy_ops.post_check_ops import evaluate_consistency_for_node_type


@pytest.mark.asyncio
async def test_post_check_uses_same_id_resolver_as_create_update_for_depend_ids(tmp_path: Path) -> None:
    db_path = tmp_path / "state.db"
    persistence = SQLitePersistenceBackend(str(db_path))
    await persistence.initialize()

    local_collection = DataCollection("local", persistence=persistence, auto_persist=False)
    remote_collection = DataCollection("remote", persistence=persistence, auto_persist=False)
    binding_manager = BindingManager(persistence, auto_persist=False)

    local_contract_data_id = "local-contract-1"
    remote_contract_data_id = "remote-contract-1"

    local_contract = ContractSyncNode(
        node_id="local-contract-node",
        data_id=local_contract_data_id,
        data={
            "id": local_contract_data_id,
            "project_id": "",
            "name": "合同A",
            "short_name": "合同A",
            "code": "C-001",
            "contract_type": "施工",
            "currency": "CNY",
            "manager_name": "张三",
            "manager_phone": "13800000000",
            "sign_company": "示例公司",
            "company_id": "company-1",
            "sign_date": "2025-01-01",
            "credit_code": None,
            "total_price": 1.0,
            "sub_name": None,
        },
        binding_status=BindingStatus.NORMAL,
        action=SyncAction.NONE,
        status=SyncStatus.SUCCESS,
    )
    remote_contract = ContractSyncNode(
        node_id="remote-contract-node",
        data_id=remote_contract_data_id,
        data={
            "id": remote_contract_data_id,
            "project_id": "",
            "name": "合同A",
            "short_name": "合同A",
            "code": "C-001",
            "contract_type": "施工",
            "currency": "CNY",
            "manager_name": "张三",
            "manager_phone": "13800000000",
            "sign_company": "示例公司",
            "company_id": "company-1",
            "sign_date": "2025-01-01",
            "credit_code": None,
            "total_price": 1.0,
            "sub_name": None,
        },
        binding_status=BindingStatus.NORMAL,
        action=SyncAction.NONE,
        status=SyncStatus.SUCCESS,
    )

    await local_collection.add(local_contract)
    await remote_collection.add(remote_contract)
    await binding_manager.bind("contract", local_contract.node_id, remote_contract.node_id)

    local_task = ConstructionTaskSyncNode(
        node_id="local-task-node",
        data_id="local-task-data-id",
        data={
            "id": "local-task-data-id",
            "project_id": "",
            "contract_id": local_contract_data_id,
            "show_name": "厂房开挖(方)",
            "construction_section": "TJ",
            "status": 0,
            "task_type": "cfkw",
            "plan_start_date": None,
            "plan_complete_date": None,
            "actual_complete_date": None,
            "complete_quantity": 0.0,
            "complete_rate": 0.0,
            "contract_quantity": None,
            "plan_node": [],
            "statistic_date": None,
            "is_crucial": False,
            "delay_days": None,
        },
        binding_status=BindingStatus.NORMAL,
        action=SyncAction.NONE,
        status=SyncStatus.SUCCESS,
    )

    remote_task = ConstructionTaskSyncNode(
        node_id="remote-task-node",
        data_id="remote-task-data-id",
        data={
            "id": "remote-task-data-id",
            "project_id": "",
            "contract_id": remote_contract_data_id,
            "show_name": "厂房开挖(方)",
            "construction_section": "TJ",
            "status": 0,
            "task_type": "cfkw",
            "plan_start_date": None,
            "plan_complete_date": None,
            "actual_complete_date": None,
            "complete_quantity": 0.0,
            "complete_rate": 0.0,
            "contract_quantity": None,
            "plan_node": [],
            "statistic_date": None,
            "is_crucial": False,
            "delay_days": None,
        },
        binding_status=BindingStatus.NORMAL,
        action=SyncAction.NONE,
        status=SyncStatus.SUCCESS,
    )

    await local_collection.add(local_task)
    await remote_collection.add(remote_task)
    await binding_manager.bind("construction_task", local_task.node_id, remote_task.node_id)

    strategy = ConstructionTaskSyncStrategy(
        "construction_task",
        local_collection,
        remote_collection,
        binding_manager,
    )

    result = await evaluate_consistency_for_node_type(
        node_type="construction_task",
        strategy=strategy,
        local_collection=local_collection,
        remote_collection=remote_collection,
        binding_manager=binding_manager,
        logger=logging.getLogger("sync_state_machine"),
        depend_fields={"contract_id": "contract"},
        compare_to_remote=True,
    )

    assert result["ok"] is True
    assert result["mismatch_count"] == 0

    await persistence.close()


@pytest.mark.asyncio
async def test_post_check_ignores_only_explicit_configured_fields(tmp_path: Path) -> None:
    db_path = tmp_path / "state.db"
    persistence = SQLitePersistenceBackend(str(db_path))
    await persistence.initialize()

    local_collection = DataCollection("local", persistence=persistence, auto_persist=False)
    remote_collection = DataCollection("remote", persistence=persistence, auto_persist=False)
    binding_manager = BindingManager(persistence, auto_persist=False)

    local_contract = ContractSyncNode(
        node_id="local-contract-node",
        data_id="local-contract-1",
        data={
            "id": "local-contract-1",
            "project_id": "",
            "name": "合同A-LOCAL",
            "short_name": "合同A",
            "code": "C-LOCAL",
            "contract_type": "施工",
            "currency": "CNY",
            "manager_name": "张三",
            "manager_phone": "13800000000",
            "sign_company": "示例公司",
            "company_id": "company-1",
            "sign_date": "2025-01-01",
            "credit_code": None,
            "total_price": 1.0,
            "sub_name": None,
        },
        binding_status=BindingStatus.NORMAL,
        action=SyncAction.NONE,
        status=SyncStatus.SUCCESS,
    )
    remote_contract = ContractSyncNode(
        node_id="remote-contract-node",
        data_id="remote-contract-1",
        data={
            "id": "remote-contract-1",
            "project_id": "",
            "name": "合同A-REMOTE",
            "short_name": "合同A",
            "code": "C-REMOTE",
            "contract_type": "施工",
            "currency": "CNY",
            "manager_name": "张三",
            "manager_phone": "13800000000",
            "sign_company": "示例公司",
            "company_id": "company-1",
            "sign_date": "2025-01-01",
            "credit_code": None,
            "total_price": 1.0,
            "sub_name": None,
        },
        binding_status=BindingStatus.NORMAL,
        action=SyncAction.NONE,
        status=SyncStatus.SUCCESS,
    )

    await local_collection.add(local_contract)
    await remote_collection.add(remote_contract)
    await binding_manager.bind("contract", local_contract.node_id, remote_contract.node_id)

    strategy = ContractSyncStrategy(
        "contract",
        local_collection,
        remote_collection,
        binding_manager,
    )

    result = await evaluate_consistency_for_node_type(
        node_type="contract",
        strategy=strategy,
        local_collection=local_collection,
        remote_collection=remote_collection,
        binding_manager=binding_manager,
        logger=logging.getLogger("sync_state_machine"),
        compare_to_remote=True,
        ignore_fields=["code"],
    )

    field_names = {field["field_name"] for field in result["fields"]}
    assert "code" not in field_names
    assert "name" in field_names
    assert result["ignore_fields"] == ["code"]

    await persistence.close()
