# #region ComplianceOrchestrator [C:5] [TYPE Module] [SEMANTICS clean-release, compliance, orchestration, stage]
# @BRIEF Execute mandatory clean compliance stages and produce final COMPLIANT/BLOCKED/FAILED outcome.
# @LAYER Domain
# @RELATION DEPENDS_ON -> [ComplianceStages]
# @RELATION DEPENDS_ON -> [RepositoryRelations]
# @RELATION DEPENDS_ON -> [CleanReleaseModels]
# @INVARIANT  COMPLIANT is impossible when any mandatory stage fails.
# @TEST_CONTRACT  ComplianceCheckRun -> ComplianceCheckRun
# @TEST_FIXTURE  compliant_candidate -> file:backend/tests/fixtures/clean_release/fixtures_clean_release.json
# @TEST_EDGE  stage_failure_blocks_release -> Mandatory stage returns FAIL and final status becomes BLOCKED
# @TEST_EDGE  missing_stage_result -> Finalization with incomplete/empty mandatory stage set must not produce COMPLIANT
# @TEST_EDGE  report_generation_error -> Downstream reporting failure does not alter orchestrator status derivation contract
# @TEST_INVARIANT  compliant_requires_all_mandatory_pass -> VERIFIED_BY: [stage_failure_blocks_release]
# @PRE  ManifestService and PolicyEngine are available
# @POST  OrchestrationResult with compliance status
# @SIDE_EFFECT  Triggers compliance checks; may modify manifest state
# @DATA_CONTRACT  Manifest -> ComplianceReport

from __future__ import annotations

from datetime import UTC, datetime
from uuid import uuid4

from ...core.logger import belief_scope, logger
from ...models.clean_release import (
    ComplianceRun,
    ComplianceStageRun,
)
from .enums import (
    ComplianceDecision,
    RunStatus,
)
from .repository import CleanReleaseRepository
from .stages import derive_final_status


# #region CleanComplianceOrchestrator [TYPE Class]
# @BRIEF Coordinate clean-release compliance verification stages.
class CleanComplianceOrchestrator:
    # region __init__ [TYPE Function]
    # @PURPOSE: Bind repository dependency used for orchestrator persistence and lookups.
    # @PRE  repository is a valid CleanReleaseRepository instance with required methods.
    # @POST  self.repository is assigned and used by all orchestration steps.
    # @SIDE_EFFECT  Stores repository reference on orchestrator instance.
    # @DATA_CONTRACT  Input -> CleanReleaseRepository, Output -> None
    def __init__(self, repository: CleanReleaseRepository):
        with belief_scope("CleanComplianceOrchestrator.__init__"):
            self.repository = repository

    # endregion __init__

    # region start_check_run [TYPE Function]
    # @PURPOSE: Initiate a new compliance run session.
    # @PRE  candidate_id and policy_id are provided; legacy callers may omit persisted manifest/policy records.
    # @POST  Returns initialized ComplianceRun in RUNNING state persisted in repository.
    # @SIDE_EFFECT  Reads manifest/policy when present and writes new ComplianceRun via repository.save_check_run.
    # @DATA_CONTRACT  Input -> (candidate_id:str, policy_id:str, requested_by:str, manifest_id:str|None), Output -> ComplianceRun
    def start_check_run(
        self,
        candidate_id: str,
        policy_id: str,
        requested_by: str | None = None,
        manifest_id: str | None = None,
        **legacy_kwargs,
    ) -> ComplianceRun:
        with belief_scope("start_check_run"):
            actor = requested_by or legacy_kwargs.get("triggered_by") or "system"
            execution_mode = (
                str(legacy_kwargs.get("execution_mode") or "").strip().lower()
            )
            manifest_id_value = manifest_id

            if manifest_id_value and str(manifest_id_value).strip().lower() in {
                "tui",
                "api",
                "scheduler",
            }:
                logger.reason(
                    "Detected legacy positional execution_mode passed through manifest_id slot",
                    extra={
                        "candidate_id": candidate_id,
                        "execution_mode": manifest_id_value,
                    },
                )
                execution_mode = str(manifest_id_value).strip().lower()
                manifest_id_value = None

            manifest = (
                self.repository.get_manifest(manifest_id_value)
                if manifest_id_value
                else None
            )
            policy = self.repository.get_policy(policy_id)

            if manifest_id_value and manifest is None:
                logger.explore(
                    "Manifest lookup missed during run start; rejecting explicit manifest contract",
                    extra={
                        "candidate_id": candidate_id,
                        "manifest_id": manifest_id_value,
                    },
                )
                raise ValueError("Manifest or Policy not found")

            if policy is None:
                logger.explore(
                    "Policy lookup missed during run start; using compatibility placeholder snapshot",
                    extra={
                        "candidate_id": candidate_id,
                        "policy_id": policy_id,
                        "execution_mode": execution_mode or "unspecified",
                    },
                )

            manifest_id_value = manifest_id_value or f"manifest-{candidate_id}"
            manifest_digest = getattr(manifest, "manifest_digest", "pending")
            registry_snapshot_id = (
                getattr(policy, "registry_snapshot_id", None)
                or getattr(policy, "internal_source_registry_ref", None)
                or "pending"
            )

            check_run = ComplianceRun(
                id=f"check-{uuid4()}",
                candidate_id=candidate_id,
                manifest_id=manifest_id_value,
                manifest_digest=manifest_digest,
                policy_snapshot_id=policy_id,
                registry_snapshot_id=registry_snapshot_id,
                requested_by=actor,
                requested_at=datetime.now(UTC),
                started_at=datetime.now(UTC),
                status=RunStatus.RUNNING,
            )
            logger.reflect(
                "Initialized compliance run with compatibility-safe dependency placeholders",
                extra={
                    "run_id": check_run.id,
                    "candidate_id": candidate_id,
                    "policy_id": policy_id,
                },
            )
            return self.repository.save_check_run(check_run)

    # endregion start_check_run

    # region execute_stages [TYPE Function]
    # @PURPOSE: Execute or accept compliance stage outcomes and set intermediate/final check-run status fields.
    # @PRE  check_run exists and references candidate/policy/registry/manifest identifiers resolvable by repository.
    # @POST  Returns persisted ComplianceRun with status FAILED on missing dependencies, otherwise SUCCEEDED with final_status set.
    # @SIDE_EFFECT  Reads candidate/policy/registry/manifest and persists updated check_run.
    # @DATA_CONTRACT  Input -> (check_run:ComplianceRun, forced_results:Optional[List[ComplianceStageRun]]), Output -> ComplianceRun
    def execute_stages(
        self,
        check_run: ComplianceRun,
        forced_results: list[ComplianceStageRun] | None = None,
    ) -> ComplianceRun:
        with belief_scope("execute_stages"):
            if forced_results is not None:
                for index, result in enumerate(forced_results, start=1):
                    if isinstance(result, ComplianceStageRun):
                        stage_run = result
                    else:
                        status_value = getattr(result, "status", None)
                        if status_value == "PASS":
                            decision = ComplianceDecision.PASSED.value
                        elif status_value == "FAIL":
                            decision = ComplianceDecision.BLOCKED.value
                        else:
                            decision = ComplianceDecision.ERROR.value
                        stage_run = ComplianceStageRun(
                            id=f"{check_run.id}-stage-{index}",
                            run_id=check_run.id,
                            stage_name=result.stage.value,
                            status=result.status.value,
                            decision=decision,
                            details_json={"details": result.details},
                        )
                    self.repository.stage_runs[stage_run.id] = stage_run

                check_run.final_status = derive_final_status(forced_results).value
                check_run.status = RunStatus.SUCCEEDED
                return self.repository.save_check_run(check_run)

            candidate = self.repository.get_candidate(check_run.candidate_id)
            policy = self.repository.get_policy(check_run.policy_snapshot_id)
            registry = self.repository.get_registry(check_run.registry_snapshot_id)
            manifest = self.repository.get_manifest(check_run.manifest_id)

            if not candidate or not policy or not registry or not manifest:
                check_run.status = RunStatus.FAILED
                check_run.finished_at = datetime.now(UTC)
                return self.repository.save_check_run(check_run)

            summary = manifest.content_json.get("summary", {})
            purity_ok = summary.get("prohibited_detected_count", 0) == 0
            check_run.final_status = (
                ComplianceDecision.PASSED.value
                if purity_ok
                else ComplianceDecision.BLOCKED.value
            )
            check_run.status = RunStatus.SUCCEEDED
            check_run.finished_at = datetime.now(UTC)

            return self.repository.save_check_run(check_run)

    # endregion execute_stages

    # region finalize_run [TYPE Function]
    # @PURPOSE: Finalize run status based on cumulative stage results.
    # @PRE  check_run was started and may already contain a derived final_status from stage execution.
    # @POST  Returns persisted ComplianceRun in SUCCEEDED status with final_status guaranteed non-empty.
    # @SIDE_EFFECT  Mutates check_run terminal fields and persists via repository.save_check_run.
    # @DATA_CONTRACT  Input -> ComplianceRun, Output -> ComplianceRun
    def finalize_run(self, check_run: ComplianceRun) -> ComplianceRun:
        with belief_scope("finalize_run"):
            if check_run.status == RunStatus.FAILED:
                check_run.finished_at = datetime.now(UTC)
                return self.repository.save_check_run(check_run)

            if not check_run.final_status:
                stage_results = [
                    stage_run
                    for stage_run in self.repository.stage_runs.values()
                    if stage_run.run_id == check_run.id
                ]
                derived = derive_final_status(stage_results)
                check_run.final_status = derived.value

            check_run.status = RunStatus.SUCCEEDED
            check_run.finished_at = datetime.now(UTC)
            return self.repository.save_check_run(check_run)

    # endregion finalize_run


# #endregion CleanComplianceOrchestrator


# #region run_check_legacy [TYPE Function]
# @BRIEF Legacy wrapper for compatibility with previous orchestrator call style.
# @PRE  repository and identifiers are valid and resolvable by orchestrator dependencies.
# @POST  Returns finalized ComplianceRun produced by orchestrator start->execute->finalize sequence.
# @SIDE_EFFECT  Reads/writes compliance entities through repository during orchestrator calls.
# @DATA_CONTRACT  Input -> (repository:CleanReleaseRepository, candidate_id:str, policy_id:str, requested_by:str, manifest_id:str), Output -> ComplianceRun
def run_check_legacy(
    repository: CleanReleaseRepository,
    candidate_id: str,
    policy_id: str,
    requested_by: str,
    manifest_id: str,
) -> ComplianceRun:
    with belief_scope("run_check_legacy"):
        orchestrator = CleanComplianceOrchestrator(repository)
        run = orchestrator.start_check_run(
            candidate_id=candidate_id,
            policy_id=policy_id,
            requested_by=requested_by,
            manifest_id=manifest_id,
        )
        run = orchestrator.execute_stages(run)
        return orchestrator.finalize_run(run)


# #endregion run_check_legacy
# #endregion ComplianceOrchestrator
