# region TestComplianceOrchestrator [TYPE Module]
# @RELATION DEPENDS_ON ->[ComplianceOrchestrator]
# @SEMANTICS: tests, clean-release, orchestrator, stage-state-machine
# @PURPOSE: Validate compliance orchestrator stage transitions and final status derivation.
# @LAYER Domain
# @INVARIANT  Failed mandatory stage forces BLOCKED terminal status.

import pytest
from unittest.mock import patch

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


# region test_orchestrator_stage_failure_blocks_release [TYPE Function]
# @RELATION  BINDS_TO -> TestComplianceOrchestrator
# @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


# endregion test_orchestrator_stage_failure_blocks_release


# region test_orchestrator_compliant_candidate [TYPE Function]
# @RELATION  BINDS_TO -> TestComplianceOrchestrator
# @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


# endregion test_orchestrator_compliant_candidate


# region test_orchestrator_missing_stage_result [TYPE Function]
# @RELATION  BINDS_TO -> TestComplianceOrchestrator
# @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


# endregion test_orchestrator_missing_stage_result


# region test_orchestrator_report_generation_error [TYPE Function]
# @RELATION  BINDS_TO -> TestComplianceOrchestrator
# @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


# endregion test_orchestrator_report_generation_error
# endregion TestComplianceOrchestrator
