from __future__ import annotations

from pydantic import BaseModel
import pytest

from sync_state_machine.common.collection import DataCollection
from sync_state_machine.common.sync_node import SyncNode
from sync_state_machine.domain.project_detail.api_handler import ProjectDetailApiHandler
from sync_state_machine.domain.project_detail.sync_node import ProjectDetailSyncNode
from sync_state_machine.datasource.task_result import TaskStatus


class _ProjectSchema(BaseModel):
    id: str


class _ProjectNode(SyncNode[_ProjectSchema]):
    node_type = "project"
    schema = _ProjectSchema


def test_project_detail_load_injects_project_id_before_validation() -> None:
    collection = DataCollection("remote")

    project = _ProjectNode(
        node_id="project-node-1",
        data_id="project-1",
        data={"id": "project-1"},
        context={
            "all_info": {
                "project_detail": [
                    {
                        "id": "detail-1",
                        "key": "plan_construction",
                        "value": [{"date": "2026-01-01", "capacity": 12.5}],
                    }
                ]
            }
        },
    )
    collection._nodes[project.node_id] = project

    handler = ProjectDetailApiHandler()
    handler.set_collection(collection)

    nodes = __import__("asyncio").run(handler.load())

    assert len(nodes) == 1
    detail_data = nodes[0].get_data()
    assert detail_data is not None
    assert detail_data["project_id"] == "project-1"
    assert detail_data["id"] == "detail-1"


class _FailingApiClient:
    async def request(self, method, endpoint, params=None, data=None, **kwargs):
        return {"code": 500, "message": "boom"}


@pytest.mark.asyncio
async def test_project_detail_create_failure_preserves_push_id_and_biz_id() -> None:
    collection = DataCollection("remote")

    project = _ProjectNode(
        node_id="project-node-1",
        data_id="project-1",
        data={"id": "project-1"},
        context={"all_info": {"project_detail": []}},
    )
    await collection.add(project)

    node = ProjectDetailSyncNode(
        node_id="detail-node-1",
        data_id="local-detail-1",
        data={
            "id": "local-detail-1",
            "project_id": "project-1",
            "key": "production",
            "value": [{"date": "2026-01-01", "capacity": 1.0}],
        },
    )

    handler = ProjectDetailApiHandler()
    handler.set_collection(collection)
    handler.api_client = _FailingApiClient()

    results = await handler.create_all([node])

    assert len(results) == 1
    result = results[0]
    assert result.status == TaskStatus.FAILED
    assert result.error == "API error: boom"
    assert isinstance(result.push_id, str) and result.push_id
    assert result.metadata["biz_id"] == "project-1"
    assert result.metadata["project_id"] == "project-1"
    assert result.metadata["key"] == "production"
