""" Endpoints API pour l'éditeur d'architecture """ from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from pydantic import BaseModel from typing import List, Optional, Dict, Any from uuid import uuid4 from datetime import datetime import json from pathlib import Path from backend.app.core.database import get_arch_db from backend.app.models.architecture import ArchitectureNode router = APIRouter(prefix="/api/architecture", tags=["Architecture"]) DATA_DIR = Path(__file__).resolve().parents[3] / "data" WORLD_FILE = DATA_DIR / "architecture.json" class ArchitectureNodeCreate(BaseModel): id: Optional[str] = None type: str x: int y: int width: int height: int rotation: int = 0 payload: Dict[str, Any] class ArchitectureNodeResponse(BaseModel): id: str type: str x: int y: int width: int height: int rotation: int payload: Dict[str, Any] created_at: datetime class Config: from_attributes = True class ArchitectureWorldPayload(BaseModel): items: List[Dict[str, Any]] splines: Optional[List[Dict[str, Any]]] = None @router.get("/nodes", response_model=List[ArchitectureNodeResponse]) async def list_nodes(db: Session = Depends(get_arch_db)): """Liste tous les noeuds d'architecture""" nodes = db.query(ArchitectureNode).order_by(ArchitectureNode.created_at.asc()).all() results = [] for node in nodes: try: payload = json.loads(node.payload or "{}") except json.JSONDecodeError: payload = {} results.append(ArchitectureNodeResponse( id=node.id, type=node.type, x=node.x, y=node.y, width=node.width, height=node.height, rotation=node.rotation, payload=payload, created_at=node.created_at )) return results @router.post("/nodes", response_model=ArchitectureNodeResponse) async def create_node(payload: ArchitectureNodeCreate, db: Session = Depends(get_arch_db)): """Créer un noeud d'architecture""" node_id = payload.id or str(uuid4()) node = ArchitectureNode( id=node_id, type=payload.type, x=payload.x, y=payload.y, width=payload.width, height=payload.height, rotation=payload.rotation, payload=json.dumps(payload.payload) ) db.add(node) db.commit() db.refresh(node) return ArchitectureNodeResponse( id=node.id, type=node.type, x=node.x, y=node.y, width=node.width, height=node.height, rotation=node.rotation, payload=payload.payload, created_at=node.created_at ) def ensure_world_file() -> None: DATA_DIR.mkdir(parents=True, exist_ok=True) if not WORLD_FILE.exists(): WORLD_FILE.write_text(json.dumps({"items": [], "splines": []}, indent=2), encoding="utf-8") @router.get("/world") async def get_world(): """Charge le fichier architecture.json, le crée si absent.""" ensure_world_file() try: data = json.loads(WORLD_FILE.read_text(encoding="utf-8")) except json.JSONDecodeError: data = {"items": [], "splines": []} return data @router.post("/world") async def save_world(payload: ArchitectureWorldPayload): """Sauvegarde les éléments du world dans architecture.json.""" ensure_world_file() splines = payload.splines or [] WORLD_FILE.write_text( json.dumps({"items": payload.items, "splines": splines}, indent=2), encoding="utf-8" ) return {"status": "ok", "count": len(payload.items), "splines": len(splines)}