"""Pattern template routes: CRUD for rectangle layout templates.""" from fastapi import APIRouter, HTTPException, Depends from wled_controller.api.auth import AuthRequired from wled_controller.api.dependencies import ( get_pattern_template_store, get_picture_target_store, ) from wled_controller.api.schemas.pattern_templates import ( PatternTemplateCreate, PatternTemplateListResponse, PatternTemplateResponse, PatternTemplateUpdate, ) from wled_controller.api.schemas.picture_targets import KeyColorRectangleSchema from wled_controller.storage.key_colors_picture_target import KeyColorRectangle from wled_controller.storage.pattern_template_store import PatternTemplateStore from wled_controller.storage.picture_target_store import PictureTargetStore from wled_controller.utils import get_logger logger = get_logger(__name__) router = APIRouter() def _pat_template_to_response(t) -> PatternTemplateResponse: """Convert a PatternTemplate to its API response.""" return PatternTemplateResponse( id=t.id, name=t.name, rectangles=[ KeyColorRectangleSchema(name=r.name, x=r.x, y=r.y, width=r.width, height=r.height) for r in t.rectangles ], created_at=t.created_at, updated_at=t.updated_at, description=t.description, ) @router.get("/api/v1/pattern-templates", response_model=PatternTemplateListResponse, tags=["Pattern Templates"]) async def list_pattern_templates( _auth: AuthRequired, store: PatternTemplateStore = Depends(get_pattern_template_store), ): """List all pattern templates.""" try: templates = store.get_all_templates() responses = [_pat_template_to_response(t) for t in templates] return PatternTemplateListResponse(templates=responses, count=len(responses)) except Exception as e: logger.error(f"Failed to list pattern templates: {e}") raise HTTPException(status_code=500, detail=str(e)) @router.post("/api/v1/pattern-templates", response_model=PatternTemplateResponse, tags=["Pattern Templates"], status_code=201) async def create_pattern_template( data: PatternTemplateCreate, _auth: AuthRequired, store: PatternTemplateStore = Depends(get_pattern_template_store), ): """Create a new pattern template.""" try: rectangles = [ KeyColorRectangle(name=r.name, x=r.x, y=r.y, width=r.width, height=r.height) for r in data.rectangles ] template = store.create_template( name=data.name, rectangles=rectangles, description=data.description, ) return _pat_template_to_response(template) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error(f"Failed to create pattern template: {e}") raise HTTPException(status_code=500, detail=str(e)) @router.get("/api/v1/pattern-templates/{template_id}", response_model=PatternTemplateResponse, tags=["Pattern Templates"]) async def get_pattern_template( template_id: str, _auth: AuthRequired, store: PatternTemplateStore = Depends(get_pattern_template_store), ): """Get pattern template by ID.""" try: template = store.get_template(template_id) return _pat_template_to_response(template) except ValueError: raise HTTPException(status_code=404, detail=f"Pattern template {template_id} not found") @router.put("/api/v1/pattern-templates/{template_id}", response_model=PatternTemplateResponse, tags=["Pattern Templates"]) async def update_pattern_template( template_id: str, data: PatternTemplateUpdate, _auth: AuthRequired, store: PatternTemplateStore = Depends(get_pattern_template_store), ): """Update a pattern template.""" try: rectangles = None if data.rectangles is not None: rectangles = [ KeyColorRectangle(name=r.name, x=r.x, y=r.y, width=r.width, height=r.height) for r in data.rectangles ] template = store.update_template( template_id=template_id, name=data.name, rectangles=rectangles, description=data.description, ) return _pat_template_to_response(template) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error(f"Failed to update pattern template: {e}") raise HTTPException(status_code=500, detail=str(e)) @router.delete("/api/v1/pattern-templates/{template_id}", status_code=204, tags=["Pattern Templates"]) async def delete_pattern_template( template_id: str, _auth: AuthRequired, store: PatternTemplateStore = Depends(get_pattern_template_store), target_store: PictureTargetStore = Depends(get_picture_target_store), ): """Delete a pattern template.""" try: if store.is_referenced_by(template_id, target_store): raise HTTPException( status_code=409, detail="Cannot delete pattern template: it is referenced by one or more key colors targets. " "Please reassign those targets before deleting.", ) store.delete_template(template_id) except HTTPException: raise except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error(f"Failed to delete pattern template: {e}") raise HTTPException(status_code=500, detail=str(e))