# #region RepositoryRelations [C:5] [TYPE Module] [SEMANTICS pydantic, clean-release, repository, relations, release]
# @BRIEF Provide repository adapter for clean release entities with deterministic access methods.
# @LAYER Infrastructure
# @RELATION DEPENDS_ON -> [CleanReleaseModels]
# @INVARIANT  Repository operations are side-effect free outside explicit save/update calls.
# @PRE  In-memory storage initialized
# @POST  Repository operations exported
# @SIDE_EFFECT  Modifies in-memory state on save/update
# @DATA_CONTRACT  Entity -> RepositoryOperation

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, cast

from ...models.clean_release import (
    CleanPolicySnapshot,
    ComplianceReport,
    ComplianceRun,
    ComplianceStageRun,
    ComplianceViolation,
    DistributionManifest,
    ReleaseCandidate,
    SourceRegistrySnapshot,
)


# #region CleanReleaseRepository [TYPE Class]
# @BRIEF Data access object for clean release lifecycle.
@dataclass
class CleanReleaseRepository:
    candidates: dict[str, ReleaseCandidate] = field(default_factory=dict)
    policies: dict[str, CleanPolicySnapshot] = field(default_factory=dict)
    registries: dict[str, SourceRegistrySnapshot] = field(default_factory=dict)
    artifacts: dict[str, object] = field(default_factory=dict)
    manifests: dict[str, DistributionManifest] = field(default_factory=dict)
    check_runs: dict[str, ComplianceRun] = field(default_factory=dict)
    stage_runs: dict[str, ComplianceStageRun] = field(default_factory=dict)
    reports: dict[str, ComplianceReport] = field(default_factory=dict)
    violations: dict[str, ComplianceViolation] = field(default_factory=dict)
    audit_events: list[dict[str, Any]] = field(default_factory=list)

    def _entity_id(self, entity: Any) -> str:
        return cast(str, str(cast(Any, entity).id))

    def _candidate_ref(self, entity: Any) -> str:
        return cast(str, str(cast(Any, entity).candidate_id))

    def _run_ref(self, entity: Any) -> str:
        return cast(str, str(cast(Any, entity).run_id))

    def save_candidate(self, candidate: ReleaseCandidate) -> ReleaseCandidate:
        cast(dict[str, ReleaseCandidate], self.candidates)[
            self._entity_id(candidate)
        ] = candidate
        return candidate

    def get_candidate(self, candidate_id: str) -> ReleaseCandidate | None:
        return self.candidates.get(candidate_id)

    def save_policy(self, policy: CleanPolicySnapshot) -> CleanPolicySnapshot:
        cast(dict[str, CleanPolicySnapshot], self.policies)[self._entity_id(policy)] = (
            policy
        )
        return policy

    def get_policy(self, policy_id: str) -> CleanPolicySnapshot | None:
        return self.policies.get(policy_id)

    def get_active_policy(self) -> CleanPolicySnapshot | None:
        # In-memory repo doesn't track 'active' flag on snapshot,
        # this should be resolved by facade using ConfigManager.
        return next(iter(self.policies.values()), None)

    def save_registry(self, registry: SourceRegistrySnapshot) -> SourceRegistrySnapshot:
        cast(dict[str, SourceRegistrySnapshot], self.registries)[
            self._entity_id(registry)
        ] = registry
        return registry

    def get_registry(self, registry_id: str) -> SourceRegistrySnapshot | None:
        return self.registries.get(registry_id)

    def save_artifact(self, artifact) -> object:
        cast(dict[str, object], self.artifacts)[self._entity_id(artifact)] = artifact
        return artifact

    def get_artifacts_by_candidate(self, candidate_id: str) -> list[object]:
        artifacts = cast(list[Any], list(self.artifacts.values()))
        return [
            artifact
            for artifact in artifacts
            if self._candidate_ref(artifact) == candidate_id
        ]

    def save_manifest(self, manifest: DistributionManifest) -> DistributionManifest:
        cast(dict[str, DistributionManifest], self.manifests)[
            self._entity_id(manifest)
        ] = manifest
        return manifest

    def get_manifest(self, manifest_id: str) -> DistributionManifest | None:
        return self.manifests.get(manifest_id)

    def save_distribution_manifest(
        self, manifest: DistributionManifest
    ) -> DistributionManifest:
        return self.save_manifest(manifest)

    def get_distribution_manifest(
        self, manifest_id: str
    ) -> DistributionManifest | None:
        return self.get_manifest(manifest_id)

    def save_check_run(self, check_run: ComplianceRun) -> ComplianceRun:
        cast(dict[str, ComplianceRun], self.check_runs)[self._entity_id(check_run)] = (
            check_run
        )
        return check_run

    def save_stage_run(self, stage_run: ComplianceStageRun) -> ComplianceStageRun:
        cast(dict[str, ComplianceStageRun], self.stage_runs)[
            self._entity_id(stage_run)
        ] = stage_run
        return stage_run

    def get_check_run(self, check_run_id: str) -> ComplianceRun | None:
        return self.check_runs.get(check_run_id)

    def save_compliance_run(self, run: ComplianceRun) -> ComplianceRun:
        return self.save_check_run(run)

    def get_compliance_run(self, run_id: str) -> ComplianceRun | None:
        return self.get_check_run(run_id)

    def save_report(self, report: ComplianceReport) -> ComplianceReport:
        report_id = self._entity_id(report)
        store = cast(dict[str, ComplianceReport], self.reports)
        existing = store.get(report_id)
        if existing is not None:
            raise ValueError(
                f"immutable report snapshot already exists for id={report_id}"
            )
        store[report_id] = report
        return report

    def get_report(self, report_id: str) -> ComplianceReport | None:
        return self.reports.get(report_id)

    def save_violation(self, violation: ComplianceViolation) -> ComplianceViolation:
        cast(dict[str, ComplianceViolation], self.violations)[
            self._entity_id(violation)
        ] = violation
        return violation

    def get_violations_by_run(self, run_id: str) -> list[ComplianceViolation]:
        violations = cast(list[ComplianceViolation], list(self.violations.values()))
        return [
            violation for violation in violations if self._run_ref(violation) == run_id
        ]

    def get_manifests_by_candidate(
        self, candidate_id: str
    ) -> list[DistributionManifest]:
        manifests = cast(list[DistributionManifest], list(self.manifests.values()))
        return [
            manifest
            for manifest in manifests
            if self._candidate_ref(manifest) == candidate_id
        ]

    def append_audit_event(self, payload: dict[str, Any]) -> None:
        self.audit_events.append(payload)

    def clear_history(self) -> None:
        self.check_runs.clear()
        self.reports.clear()
        self.violations.clear()


# #endregion CleanReleaseRepository
# #endregion RepositoryRelations
