import time from datetime import date from typing import List, Optional import oracledb from fastapi import APIRouter, Depends, HTTPException, Query, Request from shared.auth.dependencies import get_current_user from shared.auth.models import CurrentUser from shared.database.oracle_pool import oracle_pool from ..schemas.comanda import ( AsiguratorItem, ComandaListResponse, ComandaRequest, ComandaResponse, FirmaItem, InspectorItem, MasinaClientItem, MasinaDetails, OperatieItem, PartenerItem, PartnerCreateRequest, TipDevizItem, ) from ..services.comanda_service import ComandaService from ..services.lookup_service import LookupService router = APIRouter() def _server_id(request: Request) -> Optional[str]: """Extrage server_id injectat de AuthenticationMiddleware din JWT.""" return getattr(request.state, "server_id", None) def _company_id( current_user: CurrentUser, explicit: Optional[int], ) -> int: """ Rezolvă id_firma: query/body param dacă e dat, altfel prima firmă din JWT. Validează că firma e printre cele autorizate în JWT. """ if explicit is not None: cid = explicit else: if not current_user.companies: raise HTTPException(status_code=400, detail="Niciun id_firma disponibil în JWT.") cid = int(current_user.companies[0]) allowed = {int(c) for c in current_user.companies} if cid not in allowed: raise HTTPException(status_code=403, detail="Firmă neautorizată pentru utilizator.") return cid @router.get("/ping") async def ping( request: Request, _: CurrentUser = Depends(get_current_user), ): """Health check: verifies Oracle connectivity pe serverul curent.""" t0 = time.perf_counter() server_id = _server_id(request) try: async with oracle_pool.get_connection(server_id) as conn: with conn.cursor() as cursor: cursor.execute('SELECT 1 FROM DUAL') row = cursor.fetchone() except oracledb.DatabaseError as e: raise HTTPException(status_code=503, detail=f"Oracle error: {e}") elapsed_ms = round((time.perf_counter() - t0) * 1000, 2) return {"result": row[0], "server": server_id or "(default)", "latency_ms": elapsed_ms} @router.get("/firme", response_model=List[FirmaItem]) async def get_firme( request: Request, current_user: CurrentUser = Depends(get_current_user), ): """Firmele accesibile utilizatorului curent (din JWT companies[]).""" return await LookupService.get_firme(current_user.companies, _server_id(request)) @router.get("/tip-deviz", response_model=List[TipDevizItem]) async def get_tip_deviz( request: Request, id_firma: Optional[int] = Query(default=None, ge=1), current_user: CurrentUser = Depends(get_current_user), ): """Tipuri de deviz din DEV_TIP_DEVIZ (scoped pe schema firmei).""" cid = _company_id(current_user, id_firma) return await LookupService.get_tip_deviz(cid, _server_id(request)) @router.get("/masini", response_model=List[MasinaClientItem]) async def get_masini( request: Request, id_firma: Optional[int] = Query(default=None, ge=1), current_user: CurrentUser = Depends(get_current_user), ): """Mașini active din AUTO_VMASINICLIENTI (scoped pe schema firmei).""" cid = _company_id(current_user, id_firma) return await LookupService.get_masini(cid, _server_id(request)) @router.get("/comenzi", response_model=ComandaListResponse) async def list_comenzi( request: Request, page: int = Query(default=1, ge=1), per_page: int = Query(default=20, ge=1, le=100), validat: Optional[int] = Query(default=None, ge=0, le=1), data_de_la: Optional[date] = Query(default=None), data_pana_la: Optional[date] = Query(default=None), id_firma: Optional[int] = Query(default=None, ge=1), current_user: CurrentUser = Depends(get_current_user), ): # DEV_ORDL n-are id_firma; toate firmele pe aceeași schemă împart comenzile. cid = _company_id(current_user, id_firma) return await ComandaService.get_comenzi( company_id=cid, page=page, per_page=per_page, validat=validat, data_de_la=data_de_la, data_pana_la=data_pana_la, server_id=_server_id(request), ) @router.get("/asiguratori", response_model=List[AsiguratorItem]) async def get_asiguratori( request: Request, id_firma: Optional[int] = Query(default=None, ge=1), current_user: CurrentUser = Depends(get_current_user), ): """Asigurători din DEV_NOM_ASIGURATORI (scoped pe schema firmei).""" cid = _company_id(current_user, id_firma) return await LookupService.get_asiguratori(cid, _server_id(request)) @router.get("/inspectori", response_model=List[InspectorItem]) async def get_inspectori( request: Request, id_asigurator: int = Query(..., ge=1), id_firma: Optional[int] = Query(default=None, ge=1), current_user: CurrentUser = Depends(get_current_user), ): """Inspectori filtrați pe asigurator (scoped pe schema firmei).""" cid = _company_id(current_user, id_firma) return await LookupService.get_inspectori(id_asigurator, cid, _server_id(request)) @router.get("/operatii", response_model=List[OperatieItem]) async def get_operatii( request: Request, id_firma: Optional[int] = Query(default=None, ge=1), current_user: CurrentUser = Depends(get_current_user), ): """Lista completă operații DEV_NOM_NORME (scoped pe schema firmei).""" cid = _company_id(current_user, id_firma) return await LookupService.get_operatii(cid, _server_id(request)) @router.get("/parteneri", response_model=List[PartenerItem]) async def search_parteneri( request: Request, q: str = Query(..., min_length=2, max_length=100), id_firma: Optional[int] = Query(default=None, ge=1), current_user: CurrentUser = Depends(get_current_user), ): """Typeahead pe NOM_PARTENERI (scoped pe schema firmei).""" cid = _company_id(current_user, id_firma) return await LookupService.search_parteneri(q, cid, _server_id(request)) @router.post("/parteneri", response_model=PartenerItem, status_code=201) async def create_partener( data: PartnerCreateRequest, request: Request, current_user: CurrentUser = Depends(get_current_user), ): """Creează partener nou în NOM_PARTENERI (scoped pe schema firmei din JWT).""" cid = _company_id(current_user, data.id_firma) data.id_firma = cid return await LookupService.create_partener(data, _server_id(request)) @router.get("/masini/{id_masiniclient}/detalii", response_model=Optional[MasinaDetails]) async def get_masina_detalii( id_masiniclient: int, request: Request, id_firma: Optional[int] = Query(default=None, ge=1), current_user: CurrentUser = Depends(get_current_user), ): """Detalii complete mașină pentru card readonly după selecție.""" cid = _company_id(current_user, id_firma) return await LookupService.get_masina_details(id_masiniclient, cid, _server_id(request)) @router.post("/comenzi", response_model=ComandaResponse) async def creeaza_comanda( data: ComandaRequest, request: Request, current_user: CurrentUser = Depends(get_current_user), ): # data.id_firma e obligatoriu în body — validat via _company_id cid = _company_id(current_user, data.id_firma) # asigură consistența (dacă body trimite id_firma diferit de fallback) data.id_firma = cid try: return await ComandaService.creeaza_comanda( data=data, username=current_user.username, user_id=current_user.user_id, server_id=_server_id(request), ) except NotImplementedError as e: raise HTTPException(status_code=501, detail=str(e)) except ValueError as e: raise HTTPException(status_code=400, detail=str(e))