from __future__ import annotations

import json

import pytest

from app.core.common.identifiers import new_governance_uid


class FakeResult:
    def __init__(self, scalar=None):
        self.scalar = scalar

    def scalar_one(self):
        return self.scalar


class FakeSession:
    def __init__(self):
        self.calls = []

    def execute(self, statement, params=None):
        sql = str(statement)
        self.calls.append((sql, params or {}))
        if "COALESCE(MAX(version_no)" in sql:
            return FakeResult(4)
        return FakeResult()


def _spec(dataflow_uid):
    return {
        "schema_version": "1.0",
        "dataflow_uid": dataflow_uid,
        "name": "orders-read",
        "nodes": [
            {
                "id": "read_orders",
                "type": "sql.query",
                "data_source_uid": new_governance_uid(),
                "purpose": "read",
                "config": {"statement": "SELECT * FROM orders"},
            }
        ],
        "edges": [],
        "parameters": {},
    }


def _plan():
    return {
        "schema_version": "1.0",
        "timezone": "Asia/Shanghai",
        "triggers": [{"type": "manual"}],
        "max_concurrency": 1,
        "conflict_policy": "skip",
        "timeout_seconds": 600,
        "retry": {"max_attempts": 1, "delay_seconds": 0},
        "backfill": {"max_days": 1, "max_runs": 1},
    }


def test_create_workflow_version_writes_generic_version_binding_and_schedule():
    from app.core.orchestration.repository import create_workflow_version

    session = FakeSession()
    dataflow_uid = new_governance_uid()
    version_id = create_workflow_version(
        session,
        dataflow_uid=dataflow_uid,
        environment="test",
        workflow_spec=_spec(dataflow_uid),
        schedule_plan=_plan(),
        engine_type="kestra",
        engine_definition_id="dataops.orders-read.v4",
        engine_revision="sha256:abc",
        created_by=new_governance_uid(),
    )

    assert version_id
    sql = "\n".join(call[0] for call in session.calls)
    assert "INSERT INTO public.dataflow_workflow_versions" in sql
    assert "INSERT INTO public.workflow_engine_bindings" in sql
    assert "INSERT INTO public.workflow_schedules" in sql

    version_params = next(
        params
        for statement, params in session.calls
        if "INSERT INTO public.dataflow_workflow_versions" in statement
    )
    assert version_params["engine_type"] == "kestra"
    assert version_params["engine_definition_id"] == "dataops.orders-read.v4"
    assert version_params["version_no"] == 4
    assert json.loads(version_params["workflow_spec"])["dataflow_uid"] == dataflow_uid
    assert version_params["n8n_id"] is None


def test_n8n_version_keeps_legacy_mapping_while_populating_generic_fields():
    from app.core.orchestration.repository import create_workflow_version

    session = FakeSession()
    dataflow_uid = new_governance_uid()
    create_workflow_version(
        session,
        dataflow_uid=dataflow_uid,
        environment="development",
        workflow_spec=_spec(dataflow_uid),
        schedule_plan=_plan(),
        engine_type="n8n",
        engine_definition_id="legacy-n8n-id",
        created_by=new_governance_uid(),
    )

    version_params = next(
        params
        for statement, params in session.calls
        if "INSERT INTO public.dataflow_workflow_versions" in statement
    )
    assert version_params["n8n_id"] == "legacy-n8n-id"
    assert version_params["engine_definition_id"] == "legacy-n8n-id"


def test_workflow_spec_uid_must_match_repository_dataflow_uid():
    from app.core.orchestration.repository import create_workflow_version

    with pytest.raises(ValueError, match="does not match"):
        create_workflow_version(
            FakeSession(),
            dataflow_uid=new_governance_uid(),
            environment="test",
            workflow_spec=_spec(new_governance_uid()),
            schedule_plan=_plan(),
            engine_type="n8n",
            engine_definition_id="workflow-id",
            created_by=new_governance_uid(),
        )
