# #region CleanReleaseModels [C:3] [TYPE Module] [SEMANTICS sqlalchemy, clean-release, model, schema, schedule, release]
# @BRIEF Define canonical clean release domain entities and lifecycle guards.
# @LAYER Domain
# @RELATION DEPENDS_ON -> MappingModels
# @PRE  Base mapping model and release enums are available.
# @POST  Provides SQLAlchemy and dataclass definitions for governance domain.
# @SIDE_EFFECT  None (schema definition).
# @DATA_CONTRACT  Model[ReleaseCandidate, CandidateArtifact, DistributionManifest, ComplianceRun, ComplianceReport]
# @INVARIANT  Immutable snapshots are never mutated; forbidden lifecycle transitions are rejected.

from datetime import UTC, datetime
from enum import Enum
from typing import Any

from pydantic import ConfigDict, model_validator
from pydantic.dataclasses import dataclass as pydantic_dataclass
from sqlalchemy import JSON, Boolean, Column, DateTime, ForeignKey, Integer, String

from ..services.clean_release.enums import CandidateStatus, ClassificationType, ComplianceDecision, PublicationStatus, RunStatus
from ..services.clean_release.exceptions import IllegalTransitionError
from .mapping import Base


# #region ExecutionMode [TYPE Class]
# @BRIEF Backward-compatible execution mode enum for legacy TUI/orchestrator tests.
class ExecutionMode(str, Enum):
    TUI = "TUI"
    API = "API"
    SCHEDULER = "SCHEDULER"
# #endregion ExecutionMode

# #region CheckFinalStatus [TYPE Class]
# @BRIEF Backward-compatible final status enum for legacy TUI/orchestrator tests.
class CheckFinalStatus(str, Enum):
    COMPLIANT = "COMPLIANT"
    BLOCKED = "BLOCKED"
    FAILED = "FAILED"
    RUNNING = "RUNNING"
# #endregion CheckFinalStatus

# #region CheckStageName [TYPE Class]
# @BRIEF Backward-compatible stage name enum for legacy TUI/orchestrator tests.
class CheckStageName(str, Enum):
    DATA_PURITY = "DATA_PURITY"
    INTERNAL_SOURCES_ONLY = "INTERNAL_SOURCES_ONLY"
    NO_EXTERNAL_ENDPOINTS = "NO_EXTERNAL_ENDPOINTS"
    MANIFEST_CONSISTENCY = "MANIFEST_CONSISTENCY"
# #endregion CheckStageName

# #region CheckStageStatus [TYPE Class]
# @BRIEF Backward-compatible stage status enum for legacy TUI/orchestrator tests.
class CheckStageStatus(str, Enum):
    PASS = "PASS"
    FAIL = "FAIL"
    SKIPPED = "SKIPPED"
    RUNNING = "RUNNING"
# #endregion CheckStageStatus

# #region CheckStageResult [TYPE Class]
# @BRIEF Backward-compatible stage result container for legacy TUI/orchestrator tests.
@pydantic_dataclass(config=ConfigDict(validate_assignment=True))
class CheckStageResult:
    stage: CheckStageName
    status: CheckStageStatus
    details: str = ""
# #endregion CheckStageResult

# #region ProfileType [TYPE Class]
# @BRIEF Backward-compatible profile enum for legacy TUI bootstrap logic.
class ProfileType(str, Enum):
    ENTERPRISE_CLEAN = "enterprise-clean"
# #endregion ProfileType

# #region RegistryStatus [TYPE Class]
# @BRIEF Backward-compatible registry status enum for legacy TUI bootstrap logic.
class RegistryStatus(str, Enum):
    ACTIVE = "ACTIVE"
    INACTIVE = "INACTIVE"
# #endregion RegistryStatus

# #region ReleaseCandidateStatus [TYPE Class]
# @BRIEF Backward-compatible release candidate status enum for legacy TUI.
class ReleaseCandidateStatus(str, Enum):
    DRAFT = CandidateStatus.DRAFT.value
    PREPARED = CandidateStatus.PREPARED.value
    MANIFEST_BUILT = CandidateStatus.MANIFEST_BUILT.value
    CHECK_PENDING = CandidateStatus.CHECK_PENDING.value
    CHECK_RUNNING = CandidateStatus.CHECK_RUNNING.value
    CHECK_PASSED = CandidateStatus.CHECK_PASSED.value
    CHECK_BLOCKED = CandidateStatus.CHECK_BLOCKED.value
    BLOCKED = CandidateStatus.CHECK_BLOCKED.value
    CHECK_ERROR = CandidateStatus.CHECK_ERROR.value
    APPROVED = CandidateStatus.APPROVED.value
    PUBLISHED = CandidateStatus.PUBLISHED.value
    REVOKED = CandidateStatus.REVOKED.value
# #endregion ReleaseCandidateStatus

# #region ResourceSourceEntry [TYPE Class]
# @BRIEF Backward-compatible source entry model for legacy TUI bootstrap logic.
@pydantic_dataclass(config=ConfigDict(validate_assignment=True))
class ResourceSourceEntry:
    source_id: str
    host: str
    protocol: str
    purpose: str
    enabled: bool = True
# #endregion ResourceSourceEntry

# #region ResourceSourceRegistry [TYPE Class]
# @BRIEF Backward-compatible source registry model for legacy TUI bootstrap logic.
@pydantic_dataclass(config=ConfigDict(validate_assignment=True))
class ResourceSourceRegistry:
    registry_id: str
    name: str
    entries: list[ResourceSourceEntry]
    updated_at: datetime
    updated_by: str
    status: str = "ACTIVE"
    immutable: bool = True
    allowed_hosts: list[str] | None = None
    allowed_schemes: list[str] | None = None
    allowed_source_types: list[str] | None = None

    @model_validator(mode="after")
    def populate_legacy_allowlists(self):
        enabled_entries = [entry for entry in self.entries if getattr(entry, "enabled", True)]
        if self.allowed_hosts is None:
            self.allowed_hosts = [entry.host for entry in enabled_entries]
        if self.allowed_schemes is None:
            self.allowed_schemes = [entry.protocol for entry in enabled_entries]
        if self.allowed_source_types is None:
            self.allowed_source_types = [entry.purpose for entry in enabled_entries]
        return self

    @property
    def id(self) -> str:
        return self.registry_id
# #endregion ResourceSourceRegistry

# #region CleanProfilePolicy [TYPE Class]
# @BRIEF Backward-compatible policy model for legacy TUI bootstrap logic.
@pydantic_dataclass(config=ConfigDict(validate_assignment=True))
class CleanProfilePolicy:
    policy_id: str
    policy_version: str
    profile: ProfileType
    active: bool
    internal_source_registry_ref: str
    prohibited_artifact_categories: list[str]
    effective_from: datetime
    required_system_categories: list[str] | None = None
    external_source_forbidden: bool = True
    immutable: bool = True
    content_json: dict[str, Any] | None = None

    @model_validator(mode="after")
    def validate_enterprise_policy(self):
        if self.profile == ProfileType.ENTERPRISE_CLEAN:
            if not self.prohibited_artifact_categories:
                raise ValueError("enterprise-clean policy requires prohibited_artifact_categories")
            if self.external_source_forbidden is not True:
                raise ValueError("enterprise-clean policy requires external_source_forbidden=true")
        if self.content_json is None:
            self.content_json = {
                "profile": self.profile.value,
                "prohibited_artifact_categories": list(self.prohibited_artifact_categories or []),
                "required_system_categories": list(self.required_system_categories or []),
                "external_source_forbidden": self.external_source_forbidden,
            }
        return self

    @property
    def id(self) -> str:
        return self.policy_id

    @property
    def registry_snapshot_id(self) -> str:
        return self.internal_source_registry_ref
# #endregion CleanProfilePolicy

# #region ComplianceCheckRun [TYPE Class]
# @BRIEF Backward-compatible run model for legacy TUI typing/import compatibility.
@pydantic_dataclass(config=ConfigDict(validate_assignment=True))
class ComplianceCheckRun:
    check_run_id: str
    candidate_id: str
    policy_id: str
    started_at: datetime
    triggered_by: str
    execution_mode: ExecutionMode
    final_status: CheckFinalStatus
    checks: list[CheckStageResult]
    finished_at: datetime | None = None

    @model_validator(mode="after")
    def validate_final_status_alignment(self):
        mandatory_stages = {
            CheckStageName.DATA_PURITY,
            CheckStageName.INTERNAL_SOURCES_ONLY,
            CheckStageName.NO_EXTERNAL_ENDPOINTS,
            CheckStageName.MANIFEST_CONSISTENCY,
        }
        if self.final_status == CheckFinalStatus.COMPLIANT:
            observed_stages = {check.stage for check in self.checks}
            if observed_stages != mandatory_stages:
                raise ValueError("compliant run requires all mandatory stages")
            if any(check.status != CheckStageStatus.PASS for check in self.checks):
                raise ValueError("compliant run requires PASS on all mandatory stages")
        return self

    @property
    def id(self) -> str:
        return self.check_run_id

    @property
    def run_id(self) -> str:
        return self.check_run_id

    @property
    def status(self) -> RunStatus:
        if self.final_status == CheckFinalStatus.RUNNING:
            return RunStatus.RUNNING
        if self.final_status == CheckFinalStatus.BLOCKED:
            return RunStatus.FAILED
        return RunStatus.SUCCEEDED
# #endregion ComplianceCheckRun

# #region ReleaseCandidate [TYPE Class]
# @BRIEF Represents the release unit being prepared and governed.
# @PRE  id, version, source_snapshot_ref are non-empty.
# @POST  status advances only through legal transitions.
class ReleaseCandidate(Base):
    __tablename__ = "clean_release_candidates"

    id = Column(String, primary_key=True)
    name = Column(String, nullable=True) # Added back for backward compatibility with some legacy DTOs
    version = Column(String, nullable=False)
    source_snapshot_ref = Column(String, nullable=False)
    build_id = Column(String, nullable=True)
    created_at = Column(DateTime, default=lambda: datetime.now(UTC))
    created_by = Column(String, nullable=False)
    status = Column(String, default=CandidateStatus.DRAFT)

    def __init__(self, **kwargs):
        if "candidate_id" in kwargs:
            kwargs["id"] = kwargs.pop("candidate_id")
        if "profile" in kwargs:
            kwargs.pop("profile")
        status = kwargs.get("status")
        if status is None:
            kwargs["status"] = CandidateStatus.DRAFT.value
        elif isinstance(status, ReleaseCandidateStatus) or isinstance(status, CandidateStatus):
            kwargs["status"] = status.value
        if not str(kwargs.get("id", "")).strip():
            raise ValueError("candidate_id must be non-empty")
        super().__init__(**kwargs)

    @property
    def candidate_id(self) -> str:
        return self.id

    def transition_to(self, new_status: CandidateStatus):
        """
        @PURPOSE: Enforce legal state transitions.
        @PRE: Transition must be allowed by lifecycle rules.
        """
        allowed = {
            CandidateStatus.DRAFT: [CandidateStatus.PREPARED],
            CandidateStatus.PREPARED: [CandidateStatus.MANIFEST_BUILT],
            CandidateStatus.MANIFEST_BUILT: [CandidateStatus.CHECK_PENDING],
            CandidateStatus.CHECK_PENDING: [CandidateStatus.CHECK_RUNNING],
            CandidateStatus.CHECK_RUNNING: [
                CandidateStatus.CHECK_PASSED,
                CandidateStatus.CHECK_BLOCKED,
                CandidateStatus.CHECK_ERROR
            ],
            CandidateStatus.CHECK_PASSED: [CandidateStatus.APPROVED, CandidateStatus.CHECK_PENDING],
            CandidateStatus.CHECK_BLOCKED: [CandidateStatus.CHECK_PENDING],
            CandidateStatus.CHECK_ERROR: [CandidateStatus.CHECK_PENDING],
            CandidateStatus.APPROVED: [CandidateStatus.PUBLISHED],
            CandidateStatus.PUBLISHED: [CandidateStatus.REVOKED],
            CandidateStatus.REVOKED: []
        }
        current_status = CandidateStatus(self.status)
        if new_status not in allowed.get(current_status, []):
            raise IllegalTransitionError(f"Forbidden transition from {current_status} to {new_status}")
        self.status = new_status.value
# #endregion ReleaseCandidate

# #region CandidateArtifact [TYPE Class]
# @BRIEF Represents one artifact associated with a release candidate.
class CandidateArtifact(Base):
    __tablename__ = "clean_release_artifacts"

    id = Column(String, primary_key=True)
    candidate_id = Column(String, ForeignKey("clean_release_candidates.id"), nullable=False)
    path = Column(String, nullable=False)
    sha256 = Column(String, nullable=False)
    size = Column(Integer, nullable=False)
    detected_category = Column(String, nullable=True)
    declared_category = Column(String, nullable=True)
    source_uri = Column(String, nullable=True)
    source_host = Column(String, nullable=True)
    metadata_json = Column(JSON, default=dict)
# #endregion CandidateArtifact

# #region ManifestItem [TYPE Class]
@pydantic_dataclass(config=ConfigDict(validate_assignment=True))
class ManifestItem:
    path: str
    category: str
    classification: ClassificationType
    reason: str
    checksum: str | None = None
# #endregion ManifestItem

# #region ManifestSummary [TYPE Class]
@pydantic_dataclass(config=ConfigDict(validate_assignment=True))
class ManifestSummary:
    included_count: int
    excluded_count: int
    prohibited_detected_count: int
# #endregion ManifestSummary

# #region DistributionManifest [TYPE Class]
# @BRIEF Immutable snapshot of the candidate payload.
# @INVARIANT  Immutable after creation.
class DistributionManifest(Base):
    __tablename__ = "clean_release_manifests"

    id = Column(String, primary_key=True)
    candidate_id = Column(String, ForeignKey("clean_release_candidates.id"), nullable=False)
    manifest_version = Column(Integer, nullable=False)
    manifest_digest = Column(String, nullable=False)
    artifacts_digest = Column(String, nullable=False)
    created_at = Column(DateTime, default=lambda: datetime.now(UTC))
    created_by = Column(String, nullable=False)
    source_snapshot_ref = Column(String, nullable=False)
    content_json = Column(JSON, nullable=False)
    immutable = Column(Boolean, default=True)

    # Redesign compatibility fields (not persisted directly but used by builder/facade)
    def __init__(self, **kwargs):
        items = kwargs.pop("items", None)
        summary = kwargs.pop("summary", None)

        # Handle fields from manifest_builder.py
        if "manifest_id" in kwargs:
            kwargs["id"] = kwargs.pop("manifest_id")
        if "generated_at" in kwargs:
            kwargs["created_at"] = kwargs.pop("generated_at")
        if "generated_by" in kwargs:
            kwargs["created_by"] = kwargs.pop("generated_by")
        if "deterministic_hash" in kwargs:
            kwargs["manifest_digest"] = kwargs.pop("deterministic_hash")
        if "policy_id" in kwargs:
            kwargs.pop("policy_id")

        if items is not None and summary is not None:
            expected_count = int(summary.included_count) + int(summary.excluded_count)
            if expected_count != len(items):
                raise ValueError("manifest summary counts must match items size")

        # Ensure required DB fields have defaults if missing
        if "manifest_version" not in kwargs:
            kwargs["manifest_version"] = 1
        if "artifacts_digest" not in kwargs:
            kwargs["artifacts_digest"] = kwargs.get("manifest_digest", "pending")
        if "source_snapshot_ref" not in kwargs:
            kwargs["source_snapshot_ref"] = "pending"

        # Pack items and summary into content_json if provided
        if items is not None or summary is not None:
            content = dict(kwargs.get("content_json") or {})
            if items is not None:
                content["items"] = [
                    {
                        "path": i.path,
                        "category": i.category,
                        "classification": i.classification.value,
                        "reason": i.reason,
                        "checksum": i.checksum
                    } for i in items
                ]
            if summary is not None:
                content["summary"] = {
                    "included_count": summary.included_count,
                    "excluded_count": summary.excluded_count,
                    "prohibited_detected_count": summary.prohibited_detected_count
                }
            kwargs["content_json"] = content

        super().__init__(**kwargs)

    @property
    def manifest_id(self) -> str:
        return self.id

    @property
    def deterministic_hash(self) -> str:
        return self.manifest_digest

    @property
    def summary(self) -> ManifestSummary:
        payload = (self.content_json or {}).get("summary", {})
        return ManifestSummary(
            included_count=int(payload.get("included_count", 0)),
            excluded_count=int(payload.get("excluded_count", 0)),
            prohibited_detected_count=int(payload.get("prohibited_detected_count", 0)),
        )
# #endregion DistributionManifest

# #region SourceRegistrySnapshot [TYPE Class]
# @BRIEF Immutable registry snapshot for allowed sources.
class SourceRegistrySnapshot(Base):
    __tablename__ = "clean_release_registry_snapshots"

    id = Column(String, primary_key=True)
    registry_id = Column(String, nullable=False)
    registry_version = Column(String, nullable=False)
    created_at = Column(DateTime, default=lambda: datetime.now(UTC))
    allowed_hosts = Column(JSON, nullable=False) # List[str]
    allowed_schemes = Column(JSON, nullable=False) # List[str]
    allowed_source_types = Column(JSON, nullable=False) # List[str]
    immutable = Column(Boolean, default=True)
# #endregion SourceRegistrySnapshot

# #region CleanPolicySnapshot [TYPE Class]
# @BRIEF Immutable policy snapshot used to evaluate a run.
class CleanPolicySnapshot(Base):
    __tablename__ = "clean_release_policy_snapshots"

    id = Column(String, primary_key=True)
    policy_id = Column(String, nullable=False)
    policy_version = Column(String, nullable=False)
    created_at = Column(DateTime, default=lambda: datetime.now(UTC))
    content_json = Column(JSON, nullable=False)
    registry_snapshot_id = Column(String, ForeignKey("clean_release_registry_snapshots.id"), nullable=False)
    immutable = Column(Boolean, default=True)
# #endregion CleanPolicySnapshot

# #region ComplianceRun [TYPE Class]
# @BRIEF Operational record for one compliance execution.
class ComplianceRun(Base):
    __tablename__ = "clean_release_compliance_runs"

    id = Column(String, primary_key=True)
    candidate_id = Column(String, ForeignKey("clean_release_candidates.id"), nullable=False)
    manifest_id = Column(String, ForeignKey("clean_release_manifests.id"), nullable=False)
    manifest_digest = Column(String, nullable=False)
    policy_snapshot_id = Column(String, ForeignKey("clean_release_policy_snapshots.id"), nullable=False)
    registry_snapshot_id = Column(String, ForeignKey("clean_release_registry_snapshots.id"), nullable=False)
    requested_by = Column(String, nullable=False)
    requested_at = Column(DateTime, default=lambda: datetime.now(UTC))
    started_at = Column(DateTime, nullable=True)
    finished_at = Column(DateTime, nullable=True)
    status = Column(String, default=RunStatus.PENDING)
    final_status = Column(String, nullable=True) # ComplianceDecision
    failure_reason = Column(String, nullable=True)
    task_id = Column(String, nullable=True)

    @property
    def check_run_id(self) -> str:
        return self.id
# #endregion ComplianceRun

# #region ComplianceStageRun [TYPE Class]
# @BRIEF Stage-level execution record inside a run.
class ComplianceStageRun(Base):
    __tablename__ = "clean_release_compliance_stage_runs"

    id = Column(String, primary_key=True)
    run_id = Column(String, ForeignKey("clean_release_compliance_runs.id"), nullable=False)
    stage_name = Column(String, nullable=False)
    status = Column(String, nullable=False)
    started_at = Column(DateTime, nullable=True)
    finished_at = Column(DateTime, nullable=True)
    decision = Column(String, nullable=True) # ComplianceDecision
    details_json = Column(JSON, default=dict)
# #endregion ComplianceStageRun

# #region ViolationSeverity [TYPE Class]
# @BRIEF Backward-compatible violation severity enum for legacy clean-release tests.
class ViolationSeverity(str, Enum):
    CRITICAL = "CRITICAL"
    MAJOR = "MAJOR"
    MINOR = "MINOR"
# #endregion ViolationSeverity

# #region ViolationCategory [TYPE Class]
# @BRIEF Backward-compatible violation category enum for legacy clean-release tests.
class ViolationCategory(str, Enum):
    DATA_PURITY = "DATA_PURITY"
    EXTERNAL_SOURCE = "EXTERNAL_SOURCE"
    SOURCE_ISOLATION = "SOURCE_ISOLATION"
    MANIFEST_CONSISTENCY = "MANIFEST_CONSISTENCY"
    EXTERNAL_ENDPOINT = "EXTERNAL_ENDPOINT"
# #endregion ViolationCategory

# #region ComplianceViolation [TYPE Class]
# @BRIEF Violation produced by a stage.
class ComplianceViolation(Base):
    __tablename__ = "clean_release_compliance_violations"

    id = Column(String, primary_key=True)
    run_id = Column(String, ForeignKey("clean_release_compliance_runs.id"), nullable=False)
    stage_name = Column(String, nullable=False)
    code = Column(String, nullable=False)
    severity = Column(String, nullable=False)
    artifact_path = Column(String, nullable=True)
    artifact_sha256 = Column(String, nullable=True)
    message = Column(String, nullable=False)
    evidence_json = Column(JSON, default=dict)

    def __init__(self, **kwargs):
        if "violation_id" in kwargs:
            kwargs["id"] = kwargs.pop("violation_id")
        if "check_run_id" in kwargs:
            kwargs["run_id"] = kwargs.pop("check_run_id")
        if "category" in kwargs:
            category = kwargs.pop("category")
            kwargs["stage_name"] = category.value if isinstance(category, ViolationCategory) else str(category)
        if "location" in kwargs:
            kwargs["artifact_path"] = kwargs.pop("location")
        if "remediation" in kwargs:
            remediation = kwargs.pop("remediation")
            evidence = dict(kwargs.get("evidence_json") or {})
            evidence["remediation"] = remediation
            kwargs["evidence_json"] = evidence
        if "blocked_release" in kwargs:
            blocked_release = kwargs.pop("blocked_release")
            evidence = dict(kwargs.get("evidence_json") or {})
            evidence["blocked_release"] = blocked_release
            kwargs["evidence_json"] = evidence
        if "detected_at" in kwargs:
            kwargs.pop("detected_at")
        if "code" not in kwargs:
            kwargs["code"] = "LEGACY_VIOLATION"
        if "message" not in kwargs:
            kwargs["message"] = kwargs.get("stage_name", "LEGACY_VIOLATION")
        super().__init__(**kwargs)

    @property
    def violation_id(self) -> str:
        return self.id

    @violation_id.setter
    def violation_id(self, value: str) -> None:
        self.id = value

    @property
    def check_run_id(self) -> str:
        return self.run_id

    @property
    def category(self) -> ViolationCategory:
        return ViolationCategory(self.stage_name)

    @category.setter
    def category(self, value: ViolationCategory) -> None:
        self.stage_name = value.value if isinstance(value, ViolationCategory) else str(value)

    @property
    def location(self) -> str | None:
        return self.artifact_path

    @property
    def remediation(self) -> str | None:
        return (self.evidence_json or {}).get("remediation")

    @property
    def blocked_release(self) -> bool:
        return bool((self.evidence_json or {}).get("blocked_release", False))
# #endregion ComplianceViolation

# #region ComplianceReport [TYPE Class]
# @BRIEF Immutable result derived from a completed run.
# @INVARIANT  Immutable after creation.
class ComplianceReport(Base):
    __tablename__ = "clean_release_compliance_reports"

    id = Column(String, primary_key=True)
    run_id = Column(String, ForeignKey("clean_release_compliance_runs.id"), nullable=False)
    candidate_id = Column(String, ForeignKey("clean_release_candidates.id"), nullable=False)
    final_status = Column(String, nullable=False) # ComplianceDecision
    summary_json = Column(JSON, nullable=False)
    generated_at = Column(DateTime, default=lambda: datetime.now(UTC))
    immutable = Column(Boolean, default=True)

    def __init__(self, **kwargs):
        if "report_id" in kwargs:
            kwargs["id"] = kwargs.pop("report_id")
        if "check_run_id" in kwargs:
            kwargs["run_id"] = kwargs.pop("check_run_id")
        operator_summary = kwargs.pop("operator_summary", None)
        structured_payload_ref = kwargs.pop("structured_payload_ref", None)
        violations_count = kwargs.pop("violations_count", None)
        blocking_violations_count = kwargs.pop("blocking_violations_count", None)

        final_status = kwargs.get("final_status")
        final_status_value = getattr(final_status, "value", final_status)

        if (
            final_status_value in {CheckFinalStatus.BLOCKED.value, ComplianceDecision.BLOCKED.value}
            and blocking_violations_count is not None
            and int(blocking_violations_count) <= 0
        ):
            raise ValueError("blocked report requires blocking violations")

        if (
            operator_summary is not None
            or structured_payload_ref is not None
            or violations_count is not None
            or blocking_violations_count is not None
        ):
            kwargs["summary_json"] = {
                "operator_summary": operator_summary or "",
                "structured_payload_ref": structured_payload_ref,
                "violations_count": int(violations_count or 0),
                "blocking_violations_count": int(blocking_violations_count or 0),
            }

        super().__init__(**kwargs)

    @property
    def report_id(self) -> str:
        return self.id

    @property
    def check_run_id(self) -> str:
        return self.run_id

    @property
    def operator_summary(self) -> str:
        return (self.summary_json or {}).get("operator_summary", "")

    @property
    def structured_payload_ref(self) -> str | None:
        return (self.summary_json or {}).get("structured_payload_ref")

    @property
    def violations_count(self) -> int:
        return int((self.summary_json or {}).get("violations_count", 0))

    @property
    def blocking_violations_count(self) -> int:
        return int((self.summary_json or {}).get("blocking_violations_count", 0))
# #endregion ComplianceReport

# #region ApprovalDecision [TYPE Class]
# @BRIEF Approval or rejection bound to a candidate and report.
class ApprovalDecision(Base):
    __tablename__ = "clean_release_approval_decisions"

    id = Column(String, primary_key=True)
    candidate_id = Column(String, ForeignKey("clean_release_candidates.id"), nullable=False)
    report_id = Column(String, ForeignKey("clean_release_compliance_reports.id"), nullable=False)
    decision = Column(String, nullable=False) # ApprovalDecisionType
    decided_by = Column(String, nullable=False)
    decided_at = Column(DateTime, default=lambda: datetime.now(UTC))
    comment = Column(String, nullable=True)
# #endregion ApprovalDecision

# #region PublicationRecord [TYPE Class]
# @BRIEF Publication or revocation record.
class PublicationRecord(Base):
    __tablename__ = "clean_release_publication_records"

    id = Column(String, primary_key=True)
    candidate_id = Column(String, ForeignKey("clean_release_candidates.id"), nullable=False)
    report_id = Column(String, ForeignKey("clean_release_compliance_reports.id"), nullable=False)
    published_by = Column(String, nullable=False)
    published_at = Column(DateTime, default=lambda: datetime.now(UTC))
    target_channel = Column(String, nullable=False)
    publication_ref = Column(String, nullable=True)
    status = Column(String, default=PublicationStatus.ACTIVE)
# #endregion PublicationRecord

# #region CleanReleaseAuditLog [TYPE Class]
# @BRIEF Represents a persistent audit log entry for clean release actions.
import uuid


class CleanReleaseAuditLog(Base):
    __tablename__ = "clean_release_audit_logs"

    id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()))
    candidate_id = Column(String, index=True, nullable=True)
    action = Column(String, nullable=False) # e.g. "TRANSITION", "APPROVE", "PUBLISH"
    actor = Column(String, nullable=False)
    timestamp = Column(DateTime, default=lambda: datetime.now(UTC))
    details_json = Column(JSON, default=dict)
# #endregion CleanReleaseAuditLog

# #endregion CleanReleaseModels
