from typing import Dict, List from fastapi import APIRouter, Depends, HTTPException, status from pydantic import BaseModel, Field, model_validator from sqlalchemy.orm import Session from routes.dependencies import get_db from services.settings import ( CSS_COLOR_DEFAULTS, get_css_color_settings, list_css_env_override_rows, read_css_color_env_overrides, update_css_color_settings, get_theme_settings, save_theme_settings, ) router = APIRouter(prefix="/api/settings", tags=["Settings"]) class CSSSettingsPayload(BaseModel): variables: Dict[str, str] = Field(default_factory=dict) @model_validator(mode="after") def _validate_allowed_keys(self) -> "CSSSettingsPayload": invalid = set(self.variables.keys()) - set(CSS_COLOR_DEFAULTS.keys()) if invalid: invalid_keys = ", ".join(sorted(invalid)) raise ValueError( f"Unsupported CSS variables: {invalid_keys}." " Accepted keys align with the default theme variables." ) return self class EnvOverride(BaseModel): css_key: str env_var: str value: str class CSSSettingsResponse(BaseModel): variables: Dict[str, str] env_overrides: Dict[str, str] = Field(default_factory=dict) env_sources: List[EnvOverride] = Field(default_factory=list) @router.get("/css", response_model=CSSSettingsResponse) def read_css_settings(db: Session = Depends(get_db)) -> CSSSettingsResponse: try: values = get_css_color_settings(db) env_overrides = read_css_color_env_overrides() env_sources = [ EnvOverride(**row) for row in list_css_env_override_rows() ] except ValueError as exc: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(exc), ) from exc return CSSSettingsResponse( variables=values, env_overrides=env_overrides, env_sources=env_sources, ) @router.put( "/css", response_model=CSSSettingsResponse, status_code=status.HTTP_200_OK ) def update_css_settings( payload: CSSSettingsPayload, db: Session = Depends(get_db) ) -> CSSSettingsResponse: try: values = update_css_color_settings(db, payload.variables) env_overrides = read_css_color_env_overrides() env_sources = [ EnvOverride(**row) for row in list_css_env_override_rows() ] except ValueError as exc: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_CONTENT, detail=str(exc), ) from exc return CSSSettingsResponse( variables=values, env_overrides=env_overrides, env_sources=env_sources, ) class ThemeSettings(BaseModel): theme_name: str primary_color: str secondary_color: str accent_color: str background_color: str text_color: str @router.post("/theme") async def update_theme(theme_data: ThemeSettings, db: Session = Depends(get_db)): data_dict = theme_data.model_dump() save_theme_settings(db, data_dict) return {"message": "Theme updated", "theme": data_dict} @router.get("/theme") async def get_theme(db: Session = Depends(get_db)): return get_theme_settings(db)