# [DEF:backend.src.services.clean_release.preparation_service:Module]
# @TIER: STANDARD
# @SEMANTICS: clean-release, preparation, manifest, policy-evaluation
# @PURPOSE: Prepare release candidate by policy evaluation and deterministic manifest creation.
# @LAYER: Domain
# @RELATION: DEPENDS_ON -> backend.src.services.clean_release.policy_engine
# @RELATION: DEPENDS_ON -> backend.src.services.clean_release.manifest_builder
# @RELATION: DEPENDS_ON -> backend.src.services.clean_release.repository
# @INVARIANT: Candidate preparation always persists manifest and candidate status deterministically.

from __future__ import annotations

from datetime import datetime, timezone
from typing import Dict, Iterable

from .manifest_builder import build_distribution_manifest
from .policy_engine import CleanPolicyEngine
from .repository import CleanReleaseRepository
from ...models.clean_release import ReleaseCandidateStatus


def prepare_candidate(
    repository: CleanReleaseRepository,
    candidate_id: str,
    artifacts: Iterable[Dict],
    sources: Iterable[str],
    operator_id: str,
) -> Dict:
    candidate = repository.get_candidate(candidate_id)
    if candidate is None:
        raise ValueError(f"Candidate not found: {candidate_id}")

    policy = repository.get_active_policy()
    if policy is None:
        raise ValueError("Active clean policy not found")

    registry = repository.get_registry(policy.internal_source_registry_ref)
    if registry is None:
        raise ValueError("Registry not found for active policy")

    engine = CleanPolicyEngine(policy=policy, registry=registry)
    validation = engine.validate_policy()
    if not validation.ok:
        raise ValueError(f"Invalid policy: {validation.blocking_reasons}")

    classified, violations = engine.evaluate_candidate(artifacts=artifacts, sources=sources)

    manifest = build_distribution_manifest(
        manifest_id=f"manifest-{candidate_id}",
        candidate_id=candidate_id,
        policy_id=policy.policy_id,
        generated_by=operator_id,
        artifacts=classified,
    )
    repository.save_manifest(manifest)

    candidate.status = ReleaseCandidateStatus.BLOCKED if violations else ReleaseCandidateStatus.PREPARED
    repository.save_candidate(candidate)

    return {
        "candidate_id": candidate_id,
        "status": candidate.status.value,
        "manifest_id": manifest.manifest_id,
        "violations": violations,
        "prepared_at": datetime.now(timezone.utc).isoformat(),
    }
# [/DEF:backend.src.services.clean_release.preparation_service:Module]