# [DEF:backend.src.services.clean_release.repository:Module]
# @TIER: STANDARD
# @SEMANTICS: clean-release, repository, persistence, in-memory
# @PURPOSE: Provide repository adapter for clean release entities with deterministic access methods.
# @LAYER: Infra
# @RELATION: DEPENDS_ON -> backend.src.models.clean_release
# @INVARIANT: Repository operations are side-effect free outside explicit save/update calls.

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional

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


# [DEF:CleanReleaseRepository:Class]
# @PURPOSE: 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 save_candidate(self, candidate: ReleaseCandidate) -> ReleaseCandidate:
        self.candidates[candidate.id] = candidate
        return candidate

    def get_candidate(self, candidate_id: str) -> Optional[ReleaseCandidate]:
        return self.candidates.get(candidate_id)

    def save_policy(self, policy: CleanPolicySnapshot) -> CleanPolicySnapshot:
        self.policies[policy.id] = policy
        return policy

    def get_policy(self, policy_id: str) -> Optional[CleanPolicySnapshot]:
        return self.policies.get(policy_id)

    def get_active_policy(self) -> Optional[CleanPolicySnapshot]:
        # 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:
        self.registries[registry.id] = registry
        return registry

    def get_registry(self, registry_id: str) -> Optional[SourceRegistrySnapshot]:
        return self.registries.get(registry_id)

    def save_artifact(self, artifact) -> object:
        self.artifacts[artifact.id] = artifact
        return artifact

    def get_artifacts_by_candidate(self, candidate_id: str) -> List[object]:
        return [a for a in self.artifacts.values() if a.candidate_id == candidate_id]

    def save_manifest(self, manifest: DistributionManifest) -> DistributionManifest:
        self.manifests[manifest.id] = manifest
        return manifest

    def get_manifest(self, manifest_id: str) -> Optional[DistributionManifest]:
        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) -> Optional[DistributionManifest]:
        return self.get_manifest(manifest_id)

    def save_check_run(self, check_run: ComplianceRun) -> ComplianceRun:
        self.check_runs[check_run.id] = check_run
        return check_run

    def get_check_run(self, check_run_id: str) -> Optional[ComplianceRun]:
        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) -> Optional[ComplianceRun]:
        return self.get_check_run(run_id)

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

    def get_report(self, report_id: str) -> Optional[ComplianceReport]:
        return self.reports.get(report_id)

    def save_violation(self, violation: ComplianceViolation) -> ComplianceViolation:
        self.violations[violation.id] = violation
        return violation

    def get_violations_by_run(self, run_id: str) -> List[ComplianceViolation]:
        return [v for v in self.violations.values() if v.run_id == run_id]

    def get_manifests_by_candidate(self, candidate_id: str) -> List[DistributionManifest]:
        return [m for m in self.manifests.values() if m.candidate_id == candidate_id]
    def clear_history(self) -> None:
        self.check_runs.clear()
        self.reports.clear()
        self.violations.clear()
# [/DEF:CleanReleaseRepository:Class]
# [/DEF:backend.src.services.clean_release.repository:Module]