from __future__ import annotations

from kernite.evaluator import (
    evaluate_execute,
    evaluate_execute_with_context,
    execute_request,
)


def _base_request(payload: dict | None = None) -> dict:
    return {
        "workspace_id": "workspace-demo",
        "principal": {
            "type": "token",
            "id": "api:ops-bot",
        },
        "object_type": "document",
        "operation": "create",
        "payload": payload or {},
    }


def test_evaluate_execute_with_context_guardrail_deny_short_circuits_policy_eval() -> (
    None
):
    request = _base_request(payload={"title": "Q4 Plan"})
    result = evaluate_execute_with_context(
        request,
        idempotency_key="ctx-001",
        selected_policies=[
            {
                "policy_key": "document_create_allow",
                "policy_version": 1,
                "rules": [],
                "effect": "allow",
            }
        ],
        guardrail_result={
            "decision": "denied",
            "reasons": [
                {
                    "code": "invalid_target_id",
                    "message": "target_id is required.",
                    "field_path": "target_id",
                    "details": {"object_type": "document", "operation": "update"},
                }
            ],
        },
        policy_selection_reason_code="policy_selected_principal_binding",
    )

    assert result["data"]["decision"] == "denied"
    assert result["data"]["reason_codes"] == ["invalid_target_id"]
    assert (
        result["data"]["policy_selection_reason_code"]
        == "policy_selected_principal_binding"
    )


def test_evaluate_execute_with_context_applies_policy_rules() -> None:
    request = _base_request(payload={})
    result = evaluate_execute_with_context(
        request,
        idempotency_key="ctx-002",
        selected_policies=[
            {
                "policy_key": "document_create_allow",
                "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.",
                    }
                ],
            }
        ],
    )

    assert result["data"]["decision"] == "denied"
    assert result["data"]["reason_codes"] == ["missing_required_fields"]
    assert str(result["data"]["trace_hash"]).startswith("sha256:")


def test_evaluate_execute_with_context_returns_no_matching_policy_when_empty() -> None:
    request = _base_request(payload={"title": "Q4 Plan"})
    result = evaluate_execute_with_context(
        request,
        idempotency_key="ctx-003",
        selected_policies=[],
    )

    assert result["data"]["decision"] == "approved"
    assert result["data"]["reason_codes"] == ["no_matching_policy"]
    assert result["data"]["policy_selection_reason_code"] == "no_policy_found"


def test_evaluate_execute_with_context_unconditional_deny_policy() -> None:
    request = _base_request(payload={"title": "Q4 Plan"})
    result = evaluate_execute_with_context(
        request,
        idempotency_key="ctx-004",
        selected_policies=[
            {
                "policy_key": "document_create_deny",
                "policy_version": 1,
                "effect": "deny",
                "rules": [],
            }
        ],
    )

    assert result["data"]["decision"] == "denied"
    assert result["data"]["reason_codes"] == ["policy_effect_deny"]


def test_evaluate_execute_fail_closed_when_governed_without_policy() -> None:
    request = {
        **_base_request(payload={"title": "Q4 Plan"}),
        "policy_context": {
            "governed": True,
            "selected_policies": [],
        },
    }

    result = evaluate_execute(request, idempotency_key="ctx-005")

    assert result["data"]["decision"] == "denied"
    assert result["data"]["reason_codes"] == ["no_matching_policy"]
    assert result["data"]["policy_selection_reason_code"] == "no_policy_found"


def test_evaluate_execute_approves_out_of_scope_when_not_governed() -> None:
    request = _base_request(payload={"title": "Q4 Plan"})

    result = evaluate_execute(request, idempotency_key="ctx-006")

    assert result["data"]["decision"] == "approved"
    assert result["data"]["reason_codes"] == ["out_of_scope_phase1"]
    assert result["data"]["policy_selection_reason_code"] == "out_of_scope_phase1"


def test_evaluate_execute_governed_scopes_match_current_scope() -> None:
    request = {
        **_base_request(payload={"title": "Q4 Plan"}),
        "policy_context": {
            "governed_scopes": [
                {
                    "object_type": "document",
                    "operation": "create",
                }
            ],
            "selected_policies": [],
        },
    }

    result = evaluate_execute(request, idempotency_key="ctx-007")

    assert result["data"]["decision"] == "denied"
    assert result["data"]["reason_codes"] == ["no_matching_policy"]
    assert result["data"]["policy_selection_reason_code"] == "no_policy_found"


def test_evaluate_execute_associate_non_admin_is_denied_by_policy_condition() -> None:
    request = {
        "workspace_id": "workspace-demo",
        "principal": {
            "type": "token",
            "id": "api:ops-bot",
            "attributes": {
                "role": "member",
            },
        },
        "object_type": "association_edge",
        "operation": "associate",
        "payload": {"source_id": "rec-001", "target_id": "rec-002"},
        "policy_context": {
            "governed": True,
            "selected_policies": [
                {
                    "policy_key": "association_admin_only",
                    "policy_version": 1,
                    "effect": "deny",
                    "conditions": [
                        {"left": "operation", "op": "eq", "right": "associate"},
                        {
                            "left": "principal.attributes.role",
                            "op": "neq",
                            "right": "admin",
                        },
                    ],
                    "deny_reason_code": "associate_forbidden_non_admin",
                    "deny_reason_message": "Only admin can associate records.",
                    "rules": [],
                }
            ],
        },
    }

    result = evaluate_execute(request, idempotency_key="ctx-008")

    assert result["data"]["decision"] == "denied"
    assert result["data"]["reason_codes"] == ["associate_forbidden_non_admin"]


def test_evaluate_execute_associate_verified_email_condition_permits() -> None:
    request = {
        "workspace_id": "workspace-demo",
        "principal": {
            "type": "token",
            "id": "api:ops-bot",
            "attributes": {
                "hasVerifiedEmail": True,
            },
        },
        "object_type": "association_edge",
        "operation": "associate",
        "payload": {"source_id": "rec-001", "target_id": "rec-002"},
        "policy_context": {
            "governed": True,
            "selected_policies": [
                {
                    "policy_key": "association_verified_email",
                    "policy_version": 1,
                    "effect": "allow",
                    "conditions": [
                        {"left": "operation", "op": "eq", "right": "associate"},
                        {
                            "left": "principal.attributes.hasVerifiedEmail",
                            "op": "eq",
                            "right": True,
                        },
                    ],
                    "rules": [],
                }
            ],
        },
    }

    result = evaluate_execute(request, idempotency_key="ctx-009")

    assert result["data"]["decision"] == "approved"
    assert result["data"]["reason_codes"] == []


def test_evaluate_execute_associate_unverified_email_denies_with_override_reason() -> (
    None
):
    request = {
        "workspace_id": "workspace-demo",
        "principal": {
            "type": "token",
            "id": "api:ops-bot",
            "attributes": {
                "hasVerifiedEmail": False,
            },
        },
        "object_type": "association_edge",
        "operation": "associate",
        "payload": {"source_id": "rec-001", "target_id": "rec-002"},
        "policy_context": {
            "governed": True,
            "no_policy_reason_code": "associate_requires_verified_email",
            "no_policy_message": "Principal must have verified email to associate.",
            "selected_policies": [
                {
                    "policy_key": "association_verified_email",
                    "policy_version": 1,
                    "effect": "allow",
                    "conditions": [
                        {"left": "operation", "op": "eq", "right": "associate"},
                        {
                            "left": "principal.attributes.hasVerifiedEmail",
                            "op": "eq",
                            "right": True,
                        },
                    ],
                    "rules": [],
                }
            ],
        },
    }

    result = evaluate_execute(request, idempotency_key="ctx-010")

    assert result["data"]["decision"] == "denied"
    assert result["data"]["reason_codes"] == ["associate_requires_verified_email"]


def test_execute_request_returns_400_for_invalid_payload() -> None:
    status, result = execute_request(["not", "an", "object"])

    assert status == 400
    assert result["data"]["valid"] is False
    assert any(error["field"] == "body" for error in result["data"]["errors"])
