# [DEF:backend.tests.services.clean_release.test_policy_engine:Module]
# @TIER: CRITICAL
# @SEMANTICS: tests, clean-release, policy-engine, deterministic
# @PURPOSE: Validate policy model contracts and deterministic classification prerequisites for US1.
# @LAYER: Domain
# @RELATION: VERIFIES -> backend.src.models.clean_release.CleanProfilePolicy
# @INVARIANT: Enterprise policy rejects invalid activation states.

import pytest
from datetime import datetime, timezone

from src.models.clean_release import CleanProfilePolicy, ProfileType


# [DEF:test_policy_enterprise_clean_valid:Function]
# @PURPOSE: Ensure valid enterprise policy payload is accepted.
# @PRE: Fixture-like payload contains prohibited categories and registry ref.
# @POST: Model is created with external_source_forbidden=True.
def test_policy_enterprise_clean_valid():
    policy = CleanProfilePolicy(
        policy_id="policy-enterprise-clean-v1",
        policy_version="1.0.0",
        active=True,
        prohibited_artifact_categories=["test-data", "demo-data"],
        required_system_categories=["system-init"],
        external_source_forbidden=True,
        internal_source_registry_ref="registry-internal-v1",
        effective_from=datetime.now(timezone.utc),
        profile=ProfileType.ENTERPRISE_CLEAN,
    )
    assert policy.external_source_forbidden is True
    assert policy.prohibited_artifact_categories == ["test-data", "demo-data"]
# [/DEF:test_policy_enterprise_clean_valid:Function]


# [DEF:test_policy_missing_registry_fails:Function]
# @PURPOSE: Verify missing registry ref violates policy contract.
# @PRE: enterprise-clean policy payload has blank registry ref.
# @POST: Validation error is raised.
def test_policy_missing_registry_fails():
    with pytest.raises(ValueError):
        CleanProfilePolicy(
            policy_id="policy-enterprise-clean-v1",
            policy_version="1.0.0",
            active=True,
            prohibited_artifact_categories=["test-data"],
            required_system_categories=["system-init"],
            external_source_forbidden=True,
            internal_source_registry_ref="",
            effective_from=datetime.now(timezone.utc),
            profile=ProfileType.ENTERPRISE_CLEAN,
        )
# [/DEF:test_policy_missing_registry_fails:Function]


# [DEF:test_policy_empty_prohibited_categories_fails:Function]
# @PURPOSE: Verify enterprise policy cannot activate without prohibited categories.
# @PRE: enterprise-clean policy payload has empty prohibited categories.
# @POST: Validation error is raised.
def test_policy_empty_prohibited_categories_fails():
    with pytest.raises(ValueError):
        CleanProfilePolicy(
            policy_id="policy-enterprise-clean-v1",
            policy_version="1.0.0",
            active=True,
            prohibited_artifact_categories=[],
            required_system_categories=["system-init"],
            external_source_forbidden=True,
            internal_source_registry_ref="registry-internal-v1",
            effective_from=datetime.now(timezone.utc),
            profile=ProfileType.ENTERPRISE_CLEAN,
        )
# [/DEF:test_policy_empty_prohibited_categories_fails:Function]


# [DEF:test_policy_conflicting_external_forbidden_flag_fails:Function]
# @PURPOSE: Verify enterprise policy enforces external_source_forbidden=true.
# @PRE: enterprise-clean policy payload sets external_source_forbidden to false.
# @POST: Validation error is raised.
def test_policy_conflicting_external_forbidden_flag_fails():
    with pytest.raises(ValueError):
        CleanProfilePolicy(
            policy_id="policy-enterprise-clean-v1",
            policy_version="1.0.0",
            active=True,
            prohibited_artifact_categories=["test-data"],
            required_system_categories=["system-init"],
            external_source_forbidden=False,
            internal_source_registry_ref="registry-internal-v1",
            effective_from=datetime.now(timezone.utc),
            profile=ProfileType.ENTERPRISE_CLEAN,
        )
# [/DEF:test_policy_conflicting_external_forbidden_flag_fails:Function]
# [/DEF:backend.tests.services.clean_release.test_policy_engine:Module]
from src.models.clean_release import ResourceSourceRegistry, ResourceSourceEntry, RegistryStatus
from src.services.clean_release.policy_engine import CleanPolicyEngine

def _policy_enterprise_clean() -> CleanProfilePolicy:
    return CleanProfilePolicy(
        policy_id="policy-enterprise-clean-v1",
        policy_version="1.0.0",
        active=True,
        prohibited_artifact_categories=["test-data"],
        required_system_categories=["system-init"],
        external_source_forbidden=True,
        internal_source_registry_ref="registry-internal-v1",
        effective_from=datetime.now(timezone.utc),
        profile=ProfileType.ENTERPRISE_CLEAN,
    )

def _registry() -> ResourceSourceRegistry:
    return ResourceSourceRegistry(
        registry_id="registry-internal-v1",
        name="Internal",
        entries=[ResourceSourceEntry(source_id="1", host="nexus.internal", protocol="https", purpose="pkg", enabled=True)],
        updated_at=datetime.now(timezone.utc),
        updated_by="tester",
    )

# [DEF:test_policy_valid:Function]
# @PURPOSE: Validate policy valid scenario
def test_policy_valid():
    engine = CleanPolicyEngine(_policy_enterprise_clean(), _registry())
    res = engine.validate_policy()
    assert res.ok is True

# [DEF:test_conflicting_registry:Function]
# @PURPOSE: Validate policy conflicting registry edge
def test_conflicting_registry():
    reg = _registry()
    reg.registry_id = "other-registry"
    engine = CleanPolicyEngine(_policy_enterprise_clean(), reg)
    res = engine.validate_policy()
    assert res.ok is False
    assert "Policy registry ref does not match provided registry" in res.blocking_reasons

# [DEF:test_external_endpoint:Function]
# @PURPOSE: Validate policy external endpoint edge
def test_external_endpoint():
    engine = CleanPolicyEngine(_policy_enterprise_clean(), _registry())
    res = engine.validate_resource_source("external.org")
    assert res.ok is False
    assert res.violation["category"] == "external-source"

