# [DEF:backend.src.services.clean_release.stages.base:Module]
# @TIER: STANDARD
# @SEMANTICS: clean-release, compliance, stages, contracts, base
# @PURPOSE: Define shared contracts and helpers for pluggable clean-release compliance stages.
# @LAYER: Domain
# @RELATION: CALLED_BY -> backend.src.services.clean_release.compliance_execution_service
# @RELATION: DEPENDS_ON -> backend.src.models.clean_release
# @INVARIANT: Stage execution is deterministic for equal input context.

from __future__ import annotations

from dataclasses import dataclass, field
from datetime import datetime, timezone
from typing import Any, Dict, List, Protocol
from uuid import uuid4

from ....core.logger import belief_scope, logger
from ....models.clean_release import (
    CleanPolicySnapshot,
    ComplianceDecision,
    ComplianceRun,
    ComplianceStageRun,
    ComplianceViolation,
    DistributionManifest,
    ReleaseCandidate,
    SourceRegistrySnapshot,
)
from ..enums import ComplianceStageName, ViolationSeverity


# [DEF:ComplianceStageContext:Class]
# @PURPOSE: Immutable input envelope passed to each compliance stage.
@dataclass(frozen=True)
class ComplianceStageContext:
    run: ComplianceRun
    candidate: ReleaseCandidate
    manifest: DistributionManifest
    policy: CleanPolicySnapshot
    registry: SourceRegistrySnapshot
# [/DEF:ComplianceStageContext:Class]


# [DEF:StageExecutionResult:Class]
# @PURPOSE: Structured stage output containing decision, details and violations.
@dataclass
class StageExecutionResult:
    decision: ComplianceDecision
    details_json: Dict[str, Any] = field(default_factory=dict)
    violations: List[ComplianceViolation] = field(default_factory=list)
# [/DEF:StageExecutionResult:Class]


# [DEF:ComplianceStage:Class]
# @PURPOSE: Protocol for pluggable stage implementations.
class ComplianceStage(Protocol):
    stage_name: ComplianceStageName

    def execute(self, context: ComplianceStageContext) -> StageExecutionResult:
        ...
# [/DEF:ComplianceStage:Class]


# [DEF:build_stage_run_record:Function]
# @PURPOSE: Build persisted stage run record from stage result.
# @PRE: run_id and stage_name are non-empty.
# @POST: Returns ComplianceStageRun with deterministic identifiers and timestamps.
def build_stage_run_record(
    *,
    run_id: str,
    stage_name: ComplianceStageName,
    result: StageExecutionResult,
    started_at: datetime | None = None,
    finished_at: datetime | None = None,
) -> ComplianceStageRun:
    with belief_scope("build_stage_run_record"):
        now = datetime.now(timezone.utc)
        return ComplianceStageRun(
            id=f"stg-{uuid4()}",
            run_id=run_id,
            stage_name=stage_name.value,
            status="SUCCEEDED" if result.decision != ComplianceDecision.ERROR else "FAILED",
            started_at=started_at or now,
            finished_at=finished_at or now,
            decision=result.decision.value,
            details_json=result.details_json,
        )
# [/DEF:build_stage_run_record:Function]


# [DEF:build_violation:Function]
# @PURPOSE: Construct a compliance violation with normalized defaults.
# @PRE: run_id, stage_name, code and message are non-empty.
# @POST: Returns immutable-style violation payload ready for persistence.
def build_violation(
    *,
    run_id: str,
    stage_name: ComplianceStageName,
    code: str,
    message: str,
    artifact_path: str | None = None,
    severity: ViolationSeverity = ViolationSeverity.MAJOR,
    evidence_json: Dict[str, Any] | None = None,
    blocked_release: bool = True,
) -> ComplianceViolation:
    with belief_scope("build_violation"):
        logger.reflect(f"Building violation stage={stage_name.value} code={code}")
        return ComplianceViolation(
            id=f"viol-{uuid4()}",
            run_id=run_id,
            stage_name=stage_name.value,
            code=code,
            severity=severity.value,
            artifact_path=artifact_path,
            artifact_sha256=None,
            message=message,
            evidence_json={
                **(evidence_json or {}),
                "blocked_release": blocked_release,
            },
        )
# [/DEF:build_violation:Function]

# [/DEF:backend.src.services.clean_release.stages.base:Module]