# [DEF:backend.src.api.routes.clean_release_v2:Module]
# @TIER: STANDARD
# @SEMANTICS: api, clean-release, v2, headless
# @PURPOSE: Redesigned clean release API for headless candidate lifecycle.
# @LAYER: API

from fastapi import APIRouter, Depends, HTTPException, status
from typing import List, Dict, Any
from datetime import datetime, timezone
from ...services.clean_release.approval_service import approve_candidate, reject_candidate
from ...services.clean_release.publication_service import publish_candidate, revoke_publication
from ...services.clean_release.repository import CleanReleaseRepository
from ...dependencies import get_clean_release_repository
from ...services.clean_release.enums import CandidateStatus
from ...models.clean_release import ReleaseCandidate, CandidateArtifact, DistributionManifest
from ...services.clean_release.dto import CandidateDTO, ManifestDTO

router = APIRouter(prefix="/api/v2/clean-release", tags=["Clean Release V2"])


class ApprovalRequest(dict):
    pass


class PublishRequest(dict):
    pass


class RevokeRequest(dict):
    pass

@router.post("/candidates", response_model=CandidateDTO, status_code=status.HTTP_201_CREATED)
async def register_candidate(
    payload: Dict[str, Any],
    repository: CleanReleaseRepository = Depends(get_clean_release_repository)
):
    candidate = ReleaseCandidate(
        id=payload["id"],
        version=payload["version"],
        source_snapshot_ref=payload["source_snapshot_ref"],
        created_by=payload["created_by"],
        created_at=datetime.now(timezone.utc),
        status=CandidateStatus.DRAFT.value
    )
    repository.save_candidate(candidate)
    return CandidateDTO(
        id=candidate.id,
        version=candidate.version,
        source_snapshot_ref=candidate.source_snapshot_ref,
        created_at=candidate.created_at,
        created_by=candidate.created_by,
        status=CandidateStatus(candidate.status)
    )

@router.post("/candidates/{candidate_id}/artifacts")
async def import_artifacts(
    candidate_id: str,
    payload: Dict[str, Any],
    repository: CleanReleaseRepository = Depends(get_clean_release_repository)
):
    candidate = repository.get_candidate(candidate_id)
    if not candidate:
        raise HTTPException(status_code=404, detail="Candidate not found")
    
    for art_data in payload.get("artifacts", []):
        artifact = CandidateArtifact(
            id=art_data["id"],
            candidate_id=candidate_id,
            path=art_data["path"],
            sha256=art_data["sha256"],
            size=art_data["size"]
        )
        # In a real repo we'd have save_artifact
        # repository.save_artifact(artifact)
        pass
        
    return {"status": "success"}

@router.post("/candidates/{candidate_id}/manifests", response_model=ManifestDTO, status_code=status.HTTP_201_CREATED)
async def build_manifest(
    candidate_id: str,
    repository: CleanReleaseRepository = Depends(get_clean_release_repository)
):
    candidate = repository.get_candidate(candidate_id)
    if not candidate:
        raise HTTPException(status_code=404, detail="Candidate not found")
    
    manifest = DistributionManifest(
        id=f"manifest-{candidate_id}",
        candidate_id=candidate_id,
        manifest_version=1,
        manifest_digest="hash-123",
        artifacts_digest="art-hash-123",
        created_by="system",
        created_at=datetime.now(timezone.utc),
        source_snapshot_ref=candidate.source_snapshot_ref,
        content_json={"items": [], "summary": {}}
    )
    repository.save_manifest(manifest)
    
    return ManifestDTO(
        id=manifest.id,
        candidate_id=manifest.candidate_id,
        manifest_version=manifest.manifest_version,
        manifest_digest=manifest.manifest_digest,
        artifacts_digest=manifest.artifacts_digest,
        created_at=manifest.created_at,
        created_by=manifest.created_by,
        source_snapshot_ref=manifest.source_snapshot_ref,
        content_json=manifest.content_json
    )

@router.post("/candidates/{candidate_id}/approve")
async def approve_candidate_endpoint(
    candidate_id: str,
    payload: Dict[str, Any],
    repository: CleanReleaseRepository = Depends(get_clean_release_repository),
):
    try:
        decision = approve_candidate(
            repository=repository,
            candidate_id=candidate_id,
            report_id=str(payload["report_id"]),
            decided_by=str(payload["decided_by"]),
            comment=payload.get("comment"),
        )
    except Exception as exc:  # noqa: BLE001
        raise HTTPException(status_code=409, detail={"message": str(exc), "code": "APPROVAL_GATE_ERROR"})

    return {"status": "ok", "decision": decision.decision, "decision_id": decision.id}


@router.post("/candidates/{candidate_id}/reject")
async def reject_candidate_endpoint(
    candidate_id: str,
    payload: Dict[str, Any],
    repository: CleanReleaseRepository = Depends(get_clean_release_repository),
):
    try:
        decision = reject_candidate(
            repository=repository,
            candidate_id=candidate_id,
            report_id=str(payload["report_id"]),
            decided_by=str(payload["decided_by"]),
            comment=payload.get("comment"),
        )
    except Exception as exc:  # noqa: BLE001
        raise HTTPException(status_code=409, detail={"message": str(exc), "code": "APPROVAL_GATE_ERROR"})

    return {"status": "ok", "decision": decision.decision, "decision_id": decision.id}


@router.post("/candidates/{candidate_id}/publish")
async def publish_candidate_endpoint(
    candidate_id: str,
    payload: Dict[str, Any],
    repository: CleanReleaseRepository = Depends(get_clean_release_repository),
):
    try:
        publication = publish_candidate(
            repository=repository,
            candidate_id=candidate_id,
            report_id=str(payload["report_id"]),
            published_by=str(payload["published_by"]),
            target_channel=str(payload["target_channel"]),
            publication_ref=payload.get("publication_ref"),
        )
    except Exception as exc:  # noqa: BLE001
        raise HTTPException(status_code=409, detail={"message": str(exc), "code": "PUBLICATION_GATE_ERROR"})

    return {
        "status": "ok",
        "publication": {
            "id": publication.id,
            "candidate_id": publication.candidate_id,
            "report_id": publication.report_id,
            "published_by": publication.published_by,
            "published_at": publication.published_at.isoformat() if publication.published_at else None,
            "target_channel": publication.target_channel,
            "publication_ref": publication.publication_ref,
            "status": publication.status,
        },
    }


@router.post("/publications/{publication_id}/revoke")
async def revoke_publication_endpoint(
    publication_id: str,
    payload: Dict[str, Any],
    repository: CleanReleaseRepository = Depends(get_clean_release_repository),
):
    try:
        publication = revoke_publication(
            repository=repository,
            publication_id=publication_id,
            revoked_by=str(payload["revoked_by"]),
            comment=payload.get("comment"),
        )
    except Exception as exc:  # noqa: BLE001
        raise HTTPException(status_code=409, detail={"message": str(exc), "code": "PUBLICATION_GATE_ERROR"})

    return {
        "status": "ok",
        "publication": {
            "id": publication.id,
            "candidate_id": publication.candidate_id,
            "report_id": publication.report_id,
            "published_by": publication.published_by,
            "published_at": publication.published_at.isoformat() if publication.published_at else None,
            "target_channel": publication.target_channel,
            "publication_ref": publication.publication_ref,
            "status": publication.status,
        },
    }

# [/DEF:backend.src.api.routes.clean_release_v2:Module]