# region TestPolicyEngine [TYPE Module]
# @RELATION DEPENDS_ON ->[PolicyEngine]
# @PURPOSE: Contract testing for CleanPolicyEngine
# endregion TestPolicyEngine

from datetime import datetime
import pytest

from src.models.clean_release import (
    CleanProfilePolicy,
    ProfileType,
    RegistryStatus,
    ResourceSourceEntry,
    ResourceSourceRegistry,
)
from src.services.clean_release.policy_engine import CleanPolicyEngine


# @TEST_FIXTURE  policy_enterprise_clean
@pytest.fixture
def enterprise_clean_setup():
    policy = CleanProfilePolicy(
        policy_id="POL-1",
        policy_version="1",
        active=True,
        prohibited_artifact_categories=["demo", "test"],
        required_system_categories=["core"],
        internal_source_registry_ref="REG-1",
        effective_from=datetime.now(),
        profile=ProfileType.ENTERPRISE_CLEAN,
    )
    registry = ResourceSourceRegistry(
        registry_id="REG-1",
        name="Internal Registry",
        entries=[
            ResourceSourceEntry(
                source_id="S1",
                host="internal.com",
                protocol="https",
                purpose="p1",
                enabled=True,
            )
        ],
        updated_at=datetime.now(),
        updated_by="admin",
        status=RegistryStatus.ACTIVE,
    )
    return policy, registry


# @TEST_SCENARIO  policy_valid
# region test_policy_valid [TYPE Function]
# @RELATION  BINDS_TO -> TestPolicyEngine
# @PURPOSE: Verify policy validation passes when all required fields are present and valid.
def test_policy_valid(enterprise_clean_setup):
    policy, registry = enterprise_clean_setup
    engine = CleanPolicyEngine(policy, registry)
    result = engine.validate_policy()
    assert result.ok is True
    assert not result.blocking_reasons


# @TEST_EDGE  missing_registry_ref
# endregion test_policy_valid


# region test_missing_registry_ref [TYPE Function]
# @RELATION  BINDS_TO -> TestPolicyEngine
# @PURPOSE: Verify policy validation fails when registry_ref is missing.
def test_missing_registry_ref(enterprise_clean_setup):
    policy, registry = enterprise_clean_setup
    policy.internal_source_registry_ref = "  "
    engine = CleanPolicyEngine(policy, registry)
    result = engine.validate_policy()
    assert result.ok is False
    assert "Policy missing internal_source_registry_ref" in result.blocking_reasons


# @TEST_EDGE  conflicting_registry
# endregion test_missing_registry_ref


# region test_conflicting_registry [TYPE Function]
# @RELATION  BINDS_TO -> TestPolicyEngine
# @PURPOSE: Verify policy engine rejects conflicting registry references.
def test_conflicting_registry(enterprise_clean_setup):
    policy, registry = enterprise_clean_setup
    registry.registry_id = "WRONG-REG"
    engine = CleanPolicyEngine(policy, registry)
    result = engine.validate_policy()
    assert result.ok is False
    assert (
        "Policy registry ref does not match provided registry"
        in result.blocking_reasons
    )


# @TEST_INVARIANT  deterministic_classification
# endregion test_conflicting_registry


# region test_classify_artifact [TYPE Function]
# @RELATION  BINDS_TO -> TestPolicyEngine
# @PURPOSE: Verify policy engine correctly classifies artifacts based on source and type.
def test_classify_artifact(enterprise_clean_setup):
    policy, registry = enterprise_clean_setup
    engine = CleanPolicyEngine(policy, registry)

    # Required
    assert (
        engine.classify_artifact({"category": "core", "path": "p1"})
        == "required-system"
    )
    # Prohibited
    assert (
        engine.classify_artifact({"category": "demo", "path": "p2"})
        == "excluded-prohibited"
    )
    # Allowed
    assert engine.classify_artifact({"category": "others", "path": "p3"}) == "allowed"


# @TEST_EDGE  external_endpoint
# endregion test_classify_artifact


# region test_validate_resource_source [TYPE Function]
# @RELATION  BINDS_TO -> TestPolicyEngine
# @PURPOSE: Verify validate_resource_source correctly validates or rejects resource source identifiers.
def test_validate_resource_source(enterprise_clean_setup):
    policy, registry = enterprise_clean_setup
    engine = CleanPolicyEngine(policy, registry)

    # Internal (OK)
    res_ok = engine.validate_resource_source("internal.com")
    assert res_ok.ok is True

    # External (Blocked)
    res_fail = engine.validate_resource_source("external.evil")
    assert res_fail.ok is False
    assert res_fail.violation["category"] == "external-source"
    assert res_fail.violation["blocked_release"] is True


# endregion test_validate_resource_source


# region test_evaluate_candidate [TYPE Function]
# @RELATION  BINDS_TO -> TestPolicyEngine
# @PURPOSE: Verify policy engine evaluates release candidates against configured policies.
def test_evaluate_candidate(enterprise_clean_setup):
    policy, registry = enterprise_clean_setup
    engine = CleanPolicyEngine(policy, registry)

    artifacts = [
        {"path": "core.js", "category": "core"},
        {"path": "demo.sql", "category": "demo"},
    ]
    sources = ["internal.com", "google.com"]

    classified, violations = engine.evaluate_candidate(artifacts, sources)

    assert len(classified) == 2
    assert classified[0]["classification"] == "required-system"
    assert classified[1]["classification"] == "excluded-prohibited"

    # 1 violation for demo artifact + 1 for google.com source
    assert len(violations) == 2
    assert violations[0]["category"] == "data-purity"
    assert violations[1]["category"] == "external-source"


# endregion test_evaluate_candidate
