from fastapi import APIRouter, Depends, Query from app.core.config import settings from app.repositories.audit import create_audit_event from app.repositories.scheme_version_pricing import replace_scheme_version_pricing_snapshot from app.schemas.publish_preview import ( PublishPreviewResponse, RemapApplyRequest, RemapApplyResponse, RemapPreviewRequest, RemapPreviewResponse, RemapPreviewSeatItem, ) from app.schemas.publish_readiness import PublishReadinessResponse from app.security.auth import require_api_key from app.services.draft_guard import get_current_draft_context from app.services.publish_preview import get_or_build_publish_preview_bundle from app.services.publish_readiness import build_publish_readiness from app.services.remap_service import apply_remap, preview_remap router = APIRouter() @router.post(f"{settings.api_v1_prefix}/schemes/{{scheme_id}}/draft/pricing/snapshot") async def create_draft_pricing_snapshot( scheme_id: str, expected_scheme_version_id: str | None = Query(default=None), role: str = Depends(require_api_key), ): scheme, version = await get_current_draft_context( scheme_id, expected_scheme_version_id=expected_scheme_version_id, ) result = await replace_scheme_version_pricing_snapshot( scheme_id=scheme.scheme_id, scheme_version_id=version.scheme_version_id, ) await create_audit_event( scheme_id=scheme.scheme_id, event_type="draft.pricing.snapshot.created", object_type="pricing_snapshot", object_ref=version.scheme_version_id, details=result, ) return { "scheme_id": scheme.scheme_id, "scheme_version_id": version.scheme_version_id, **result, } @router.get( f"{settings.api_v1_prefix}/schemes/{{scheme_id}}/draft/publish-preview", response_model=PublishPreviewResponse, ) async def get_publish_preview( scheme_id: str, baseline_scheme_version_id: str | None = Query(default=None), refresh: bool = Query(default=False), expected_scheme_version_id: str | None = Query(default=None), role: str = Depends(require_api_key), ): scheme, version = await get_current_draft_context( scheme_id, expected_scheme_version_id=expected_scheme_version_id, ) bundle = await get_or_build_publish_preview_bundle( scheme_id=scheme.scheme_id, scheme_version_id=version.scheme_version_id, baseline_override_scheme_version_id=baseline_scheme_version_id, refresh=refresh, ) return PublishPreviewResponse( scheme_id=scheme.scheme_id, scheme_version_id=version.scheme_version_id, artifacts=bundle["artifacts"], validation=bundle["validation"], structure_diff=bundle["structure_diff"], pricing_coverage=bundle["pricing_coverage"], summary=bundle["summary"], ) @router.get( f"{settings.api_v1_prefix}/schemes/{{scheme_id}}/draft/publish-readiness", response_model=PublishReadinessResponse, ) async def get_publish_readiness( scheme_id: str, expected_scheme_version_id: str | None = Query(default=None), role: str = Depends(require_api_key), ): scheme, version = await get_current_draft_context( scheme_id, expected_scheme_version_id=expected_scheme_version_id, ) readiness = await build_publish_readiness( scheme_id=scheme.scheme_id, scheme_version_id=version.scheme_version_id, status=version.status, ) return PublishReadinessResponse(**readiness) @router.post( f"{settings.api_v1_prefix}/schemes/{{scheme_id}}/draft/remap/preview", response_model=RemapPreviewResponse, ) async def preview_draft_remap( scheme_id: str, payload: RemapPreviewRequest, expected_scheme_version_id: str | None = Query(default=None), role: str = Depends(require_api_key), ): scheme, version = await get_current_draft_context( scheme_id, expected_scheme_version_id=expected_scheme_version_id, ) items = await preview_remap( scheme_version_id=version.scheme_version_id, seat_record_ids=payload.seat_record_ids, from_sector_id=payload.from_sector_id, to_sector_id=payload.to_sector_id, from_group_id=payload.from_group_id, to_group_id=payload.to_group_id, ) return RemapPreviewResponse( scheme_id=scheme.scheme_id, scheme_version_id=version.scheme_version_id, matched_count=len(items), items=[RemapPreviewSeatItem(**item) for item in items], ) @router.post( f"{settings.api_v1_prefix}/schemes/{{scheme_id}}/draft/remap/apply", response_model=RemapApplyResponse, ) async def apply_draft_remap( scheme_id: str, payload: RemapApplyRequest, expected_scheme_version_id: str | None = Query(default=None), role: str = Depends(require_api_key), ): scheme, version = await get_current_draft_context( scheme_id, expected_scheme_version_id=expected_scheme_version_id, ) items = await apply_remap( scheme_version_id=version.scheme_version_id, seat_record_ids=payload.seat_record_ids, from_sector_id=payload.from_sector_id, to_sector_id=payload.to_sector_id, from_group_id=payload.from_group_id, to_group_id=payload.to_group_id, ) await create_audit_event( scheme_id=scheme.scheme_id, event_type="draft.remap.applied", object_type="draft_structure", object_ref=version.scheme_version_id, details={ "matched_count": len(items), "from_sector_id": payload.from_sector_id, "to_sector_id": payload.to_sector_id, "from_group_id": payload.from_group_id, "to_group_id": payload.to_group_id, }, ) return RemapApplyResponse( scheme_id=scheme.scheme_id, scheme_version_id=version.scheme_version_id, updated_count=len(items), items=[RemapPreviewSeatItem(**item) for item in items], )