# [DEF:backend.tests.services.clean_release.test_compliance_orchestrator:Module]
# @TIER: STANDARD
# @SEMANTICS: tests, clean-release, orchestrator, stage-state-machine
# @PURPOSE: Validate compliance orchestrator stage transitions and final status derivation.
# @LAYER: Domain
# @RELATION: TESTS -> backend.src.services.clean_release.compliance_orchestrator
# @INVARIANT: Failed mandatory stage forces BLOCKED terminal status.

from unittest.mock import patch

import pytest

from src.models.clean_release import (
    CheckFinalStatus,
    CheckStageName,
    CheckStageResult,
    CheckStageStatus,
)
from src.services.clean_release.compliance_orchestrator import CleanComplianceOrchestrator
from src.services.clean_release.report_builder import ComplianceReportBuilder
from src.services.clean_release.repository import CleanReleaseRepository


# [DEF:test_orchestrator_stage_failure_blocks_release:Function]
# @PURPOSE: Verify mandatory stage failure forces BLOCKED final status.
def test_orchestrator_stage_failure_blocks_release():
    repository = CleanReleaseRepository()
    orchestrator = CleanComplianceOrchestrator(repository)

    run = orchestrator.start_check_run(
        candidate_id="2026.03.03-rc1",
        policy_id="policy-enterprise-clean-v1",
        triggered_by="tester",
        execution_mode="tui",
    )
    run = orchestrator.execute_stages(
        run,
        forced_results=[
            CheckStageResult(stage=CheckStageName.DATA_PURITY, status=CheckStageStatus.PASS, details="ok"),
            CheckStageResult(stage=CheckStageName.INTERNAL_SOURCES_ONLY, status=CheckStageStatus.PASS, details="ok"),
            CheckStageResult(stage=CheckStageName.NO_EXTERNAL_ENDPOINTS, status=CheckStageStatus.FAIL, details="external"),
            CheckStageResult(stage=CheckStageName.MANIFEST_CONSISTENCY, status=CheckStageStatus.PASS, details="ok"),
        ],
    )
    run = orchestrator.finalize_run(run)

    assert run.final_status == CheckFinalStatus.BLOCKED
# [/DEF:test_orchestrator_stage_failure_blocks_release:Function]


# [DEF:test_orchestrator_compliant_candidate:Function]
# @PURPOSE: Verify happy path where all mandatory stages pass yields COMPLIANT.
def test_orchestrator_compliant_candidate():
    repository = CleanReleaseRepository()
    orchestrator = CleanComplianceOrchestrator(repository)

    run = orchestrator.start_check_run(
        candidate_id="2026.03.03-rc1",
        policy_id="policy-enterprise-clean-v1",
        triggered_by="tester",
        execution_mode="tui",
    )
    run = orchestrator.execute_stages(
        run,
        forced_results=[
            CheckStageResult(stage=CheckStageName.DATA_PURITY, status=CheckStageStatus.PASS, details="ok"),
            CheckStageResult(stage=CheckStageName.INTERNAL_SOURCES_ONLY, status=CheckStageStatus.PASS, details="ok"),
            CheckStageResult(stage=CheckStageName.NO_EXTERNAL_ENDPOINTS, status=CheckStageStatus.PASS, details="ok"),
            CheckStageResult(stage=CheckStageName.MANIFEST_CONSISTENCY, status=CheckStageStatus.PASS, details="ok"),
        ],
    )
    run = orchestrator.finalize_run(run)

    assert run.final_status == CheckFinalStatus.COMPLIANT
# [/DEF:test_orchestrator_compliant_candidate:Function]


# [DEF:test_orchestrator_missing_stage_result:Function]
# @PURPOSE: Verify incomplete mandatory stage set cannot end as COMPLIANT and results in FAILED.
def test_orchestrator_missing_stage_result():
    repository = CleanReleaseRepository()
    orchestrator = CleanComplianceOrchestrator(repository)

    run = orchestrator.start_check_run("cand-1", "pol-1", "tester", "tui")
    run = orchestrator.execute_stages(
        run,
        forced_results=[CheckStageResult(stage=CheckStageName.DATA_PURITY, status=CheckStageStatus.PASS, details="ok")],
    )
    run = orchestrator.finalize_run(run)

    assert run.final_status == CheckFinalStatus.FAILED
# [/DEF:test_orchestrator_missing_stage_result:Function]


# [DEF:test_orchestrator_report_generation_error:Function]
# @PURPOSE: Verify downstream report errors do not mutate orchestrator final status.
def test_orchestrator_report_generation_error():
    repository = CleanReleaseRepository()
    orchestrator = CleanComplianceOrchestrator(repository)

    run = orchestrator.start_check_run("cand-1", "pol-1", "tester", "tui")
    run = orchestrator.finalize_run(run)
    assert run.final_status == CheckFinalStatus.FAILED

    with patch.object(ComplianceReportBuilder, "build_report_payload", side_effect=ValueError("Report error")):
        builder = ComplianceReportBuilder(repository)
        with pytest.raises(ValueError, match="Report error"):
            builder.build_report_payload(run, [])

    assert run.final_status == CheckFinalStatus.FAILED
# [/DEF:test_orchestrator_report_generation_error:Function]
# [/DEF:backend.tests.services.clean_release.test_compliance_orchestrator:Module]
