from __future__ import annotations

from kernite.validation import validate_execute_request


def test_validate_execute_request_valid_payload() -> None:
    payload = {
        "workspace_id": "workspace-demo",
        "principal": {
            "type": "token",
            "id": "api:billing-bot",
        },
        "object_type": "invoice",
        "operation": "create",
        "payload": {
            "currency": "USD",
        },
    }

    result = validate_execute_request(payload, idempotency_key="demo-001")

    assert result["message"] == "Execute payload is valid."
    assert result["data"]["valid"] is True
    assert result["data"]["errors"] == []
    assert result["data"]["normalized"]["object_type"] == "invoice"
    assert result["data"]["normalized"]["operation"] == "create"
    assert result["data"]["normalized"]["idempotency_key"] == "demo-001"


def test_validate_execute_request_valid_payload_with_policy_context() -> None:
    payload = {
        "workspace_id": "workspace-demo",
        "principal": {
            "type": "token",
            "id": "api:ops-bot",
        },
        "object_type": "document",
        "operation": "create",
        "payload": {
            "title": "Q4 Plan",
        },
        "policy_context": {
            "governed": True,
            "selected_policies": [
                {
                    "policy_key": "document_create_default",
                    "policy_version": 1,
                    "effect": "allow",
                    "rules": [
                        {
                            "rule_key": "require_title",
                            "rule_definition": {
                                "type": "required_fields",
                                "fields": ["title"],
                            },
                            "reason_code": "missing_required_fields",
                            "reason_message": "title is required.",
                        }
                    ],
                }
            ],
        },
    }

    result = validate_execute_request(payload)

    assert result["data"]["valid"] is True
    normalized_context = result["data"]["normalized"]["policy_context"]
    assert normalized_context["governed"] is True
    assert (
        normalized_context["selected_policies"][0]["policy_key"]
        == "document_create_default"
    )


def test_validate_execute_request_invalid_payload() -> None:
    payload = {
        "workspace_id": "",
        "principal": {
            "type": "",
            "id": "",
        },
        "object_type": "",
        "operation": "run",
        "payload": [],
    }

    result = validate_execute_request(payload)

    assert result["message"] == "Execute payload is invalid."
    assert result["data"]["valid"] is False
    fields = {error["field"] for error in result["data"]["errors"]}
    assert "workspace_id" in fields
    assert "object_type" in fields
    assert "operation" in fields
    assert "payload" in fields
    assert "principal.type" in fields
    assert "principal.id" in fields


def test_validate_execute_request_invalid_policy_context_shape() -> None:
    payload = {
        "workspace_id": "workspace-demo",
        "principal": {
            "type": "token",
            "id": "api:ops-bot",
        },
        "object_type": "document",
        "operation": "create",
        "payload": {},
        "policy_context": {
            "governed": "yes",
            "selected_policies": {
                "policy_key": "invalid",
            },
        },
    }

    result = validate_execute_request(payload)

    assert result["data"]["valid"] is False
    fields = {error["field"] for error in result["data"]["errors"]}
    assert "policy_context.governed" in fields
    assert "policy_context.selected_policies" in fields


def test_validate_execute_request_non_object_body() -> None:
    result = validate_execute_request(["not", "an", "object"])

    assert result["data"]["valid"] is False
    fields = {error["field"] for error in result["data"]["errors"]}
    assert "body" in fields


def test_validate_execute_request_supports_associate_with_parc_inputs() -> None:
    payload = {
        "workspace_id": "workspace-demo",
        "principal": {
            "type": "token",
            "id": "api:ops-bot",
            "attributes": {
                "role": "admin",
                "hasVerifiedEmail": True,
            },
        },
        "object_type": "association_edge",
        "operation": "associate",
        "resource": {
            "type": "association_edge",
            "id": "assoc-edge-001",
        },
        "context": {
            "source": "internal",
        },
        "payload": {
            "source_id": "rec-001",
            "target_id": "rec-002",
        },
    }

    result = validate_execute_request(payload)

    assert result["data"]["valid"] is True
    normalized = result["data"]["normalized"]
    assert normalized["operation"] == "associate"
    assert normalized["principal"]["attributes"]["role"] == "admin"
    assert normalized["resource"]["type"] == "association_edge"
    assert normalized["context"]["source"] == "internal"


def test_validate_execute_request_rejects_invalid_parc_shapes() -> None:
    payload = {
        "workspace_id": "workspace-demo",
        "principal": {
            "type": "token",
            "id": "api:ops-bot",
            "attributes": "not-an-object",
        },
        "object_type": "association_edge",
        "operation": "associate",
        "resource": [],
        "context": [],
        "payload": {},
    }

    result = validate_execute_request(payload)

    assert result["data"]["valid"] is False
    fields = {error["field"] for error in result["data"]["errors"]}
    assert "principal.attributes" in fields
    assert "resource" in fields
    assert "context" in fields
