# [DEF:__tests__/test_clean_release:Module]
# @RELATION: VERIFIES -> ../clean_release.py
# @PURPOSE: Contract testing for Clean Release models
# [/DEF:__tests__/test_clean_release:Module]

import pytest
from datetime import datetime
from pydantic import ValidationError
from src.models.clean_release import (
    ReleaseCandidate, 
    ReleaseCandidateStatus, 
    ProfileType, 
    CleanProfilePolicy, 
    DistributionManifest,
    ManifestItem,
    ManifestSummary,
    ClassificationType,
    ComplianceCheckRun,
    CheckFinalStatus,
    CheckStageResult,
    CheckStageName,
    CheckStageStatus,
    ComplianceReport,
    ExecutionMode
)

# @TEST_FIXTURE: valid_enterprise_candidate
@pytest.fixture
def valid_candidate_data():
    return {
        "candidate_id": "RC-001",
        "version": "1.0.0",
        "profile": ProfileType.ENTERPRISE_CLEAN,
        "created_at": datetime.now(),
        "created_by": "admin",
        "source_snapshot_ref": "v1.0.0-snapshot"
    }

def test_release_candidate_valid(valid_candidate_data):
    rc = ReleaseCandidate(**valid_candidate_data)
    assert rc.candidate_id == "RC-001"
    assert rc.status == ReleaseCandidateStatus.DRAFT

def test_release_candidate_empty_id(valid_candidate_data):
    valid_candidate_data["candidate_id"] = "  "
    with pytest.raises(ValueError, match="candidate_id must be non-empty"):
        ReleaseCandidate(**valid_candidate_data)

# @TEST_FIXTURE: valid_enterprise_policy
@pytest.fixture
def valid_policy_data():
    return {
        "policy_id": "POL-001",
        "policy_version": "1",
        "active": True,
        "prohibited_artifact_categories": ["test-data"],
        "required_system_categories": ["core"],
        "internal_source_registry_ref": "REG-1",
        "effective_from": datetime.now(),
        "profile": ProfileType.ENTERPRISE_CLEAN
    }

# @TEST_INVARIANT: policy_purity
def test_enterprise_policy_valid(valid_policy_data):
    policy = CleanProfilePolicy(**valid_policy_data)
    assert policy.external_source_forbidden is True

# @TEST_EDGE: enterprise_policy_missing_prohibited
def test_enterprise_policy_missing_prohibited(valid_policy_data):
    valid_policy_data["prohibited_artifact_categories"] = []
    with pytest.raises(ValueError, match="enterprise-clean policy requires prohibited_artifact_categories"):
        CleanProfilePolicy(**valid_policy_data)

# @TEST_EDGE: enterprise_policy_external_allowed
def test_enterprise_policy_external_allowed(valid_policy_data):
    valid_policy_data["external_source_forbidden"] = False
    with pytest.raises(ValueError, match="enterprise-clean policy requires external_source_forbidden=true"):
        CleanProfilePolicy(**valid_policy_data)

# @TEST_INVARIANT: manifest_consistency
# @TEST_EDGE: manifest_count_mismatch
def test_manifest_count_mismatch():
    summary = ManifestSummary(included_count=1, excluded_count=0, prohibited_detected_count=0)
    item = ManifestItem(path="p", category="c", classification=ClassificationType.ALLOWED, reason="r")
    
    # Valid
    DistributionManifest(
        manifest_id="m1", candidate_id="rc1", policy_id="p1", 
        generated_at=datetime.now(), generated_by="u", items=[item], 
        summary=summary, deterministic_hash="h"
    )
    
    # Invalid count
    summary.included_count = 2
    with pytest.raises(ValueError, match="manifest summary counts must match items size"):
        DistributionManifest(
            manifest_id="m1", candidate_id="rc1", policy_id="p1", 
            generated_at=datetime.now(), generated_by="u", items=[item], 
            summary=summary, deterministic_hash="h"
        )

# @TEST_INVARIANT: run_integrity
# @TEST_EDGE: compliant_run_stage_fail
def test_compliant_run_validation():
    base_run = {
        "check_run_id": "run1",
        "candidate_id": "rc1",
        "policy_id": "p1",
        "started_at": datetime.now(),
        "triggered_by": "u",
        "execution_mode": ExecutionMode.TUI,
        "final_status": CheckFinalStatus.COMPLIANT,
        "checks": [
            CheckStageResult(stage=CheckStageName.DATA_PURITY, status=CheckStageStatus.PASS),
            CheckStageResult(stage=CheckStageName.INTERNAL_SOURCES_ONLY, status=CheckStageStatus.PASS),
            CheckStageResult(stage=CheckStageName.NO_EXTERNAL_ENDPOINTS, status=CheckStageStatus.PASS),
            CheckStageResult(stage=CheckStageName.MANIFEST_CONSISTENCY, status=CheckStageStatus.PASS),
        ]
    }
    # Valid
    ComplianceCheckRun(**base_run)
    
    # One stage fails -> cannot be COMPLIANT
    base_run["checks"][0].status = CheckStageStatus.FAIL
    with pytest.raises(ValueError, match="compliant run requires PASS on all mandatory stages"):
        ComplianceCheckRun(**base_run)
        
    # Missing stage -> cannot be COMPLIANT
    base_run["checks"] = base_run["checks"][1:]
    with pytest.raises(ValueError, match="compliant run requires all mandatory stages"):
        ComplianceCheckRun(**base_run)

def test_report_validation():
    # Valid blocked report
    ComplianceReport(
        report_id="rep1", check_run_id="run1", candidate_id="rc1",
        generated_at=datetime.now(), final_status=CheckFinalStatus.BLOCKED,
        operator_summary="Blocked", structured_payload_ref="ref",
        violations_count=2, blocking_violations_count=2
    )
    
    # BLOCKED with 0 blocking violations
    with pytest.raises(ValueError, match="blocked report requires blocking violations"):
        ComplianceReport(
            report_id="rep1", check_run_id="run1", candidate_id="rc1",
            generated_at=datetime.now(), final_status=CheckFinalStatus.BLOCKED,
            operator_summary="Blocked", structured_payload_ref="ref",
            violations_count=2, blocking_violations_count=0
        )
