from __future__ import annotations from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy import select from sqlalchemy.orm import Session from app.api.deps import get_current_user, get_db from app.models.booking import Booking from app.models.customer import Customer from app.models.data_quality import DataQualityIssue from app.models.inspection import Inspection from app.models.maintenance import MaintenanceRecord from app.models.vehicle import Vehicle from app.schemas import ( BookingSummaryOut, CurrentUser, DataQualityIssueOut, InspectionOut, MaintenanceOut, VehicleDetailOut, VehicleOut, ) router = APIRouter(prefix="/api/v1/vehicles", tags=["vehicles"]) def _attention_vehicle_ids(db: Session) -> set: rows = db.scalars( select(DataQualityIssue.entity_id).where( DataQualityIssue.entity_type == "vehicle", DataQualityIssue.status == "open", ) ).all() return set(rows) @router.get("", response_model=list[VehicleOut]) def list_vehicles( status: str | None = Query(default=None), attention_only: bool = Query(default=False), db: Session = Depends(get_db), _user: CurrentUser = Depends(get_current_user), ) -> list[VehicleOut]: stmt = select(Vehicle).order_by(Vehicle.public_ref) if status: stmt = stmt.where(Vehicle.operational_status == status) vehicles = db.scalars(stmt).all() attention_ids = _attention_vehicle_ids(db) out = [ VehicleOut( public_ref=v.public_ref, make=v.make, model=v.model, model_year=v.model_year, registration_number=v.registration_number, location=v.location, operational_status=v.operational_status, odometer_km=v.odometer_km, next_service_km=v.next_service_km, active=v.active, attention=v.id in attention_ids or v.operational_status == "blocked", ) for v in vehicles ] if attention_only: out = [v for v in out if v.attention] return out @router.get("/{public_ref}", response_model=VehicleDetailOut) def get_vehicle( public_ref: str, db: Session = Depends(get_db), _user: CurrentUser = Depends(get_current_user), ) -> VehicleDetailOut: vehicle = db.scalar(select(Vehicle).where(Vehicle.public_ref == public_ref)) if vehicle is None: raise HTTPException(status_code=404, detail="Vehicle not found") bookings = db.scalars( select(Booking).where(Booking.vehicle_id == vehicle.id).order_by(Booking.starts_at.desc()) ).all() customer_ref_by_id = {c.id: c.public_ref for c in db.scalars(select(Customer)).all()} inspections = db.scalars( select(Inspection) .where(Inspection.vehicle_id == vehicle.id) .order_by(Inspection.completed_at.desc()) ).all() maintenance = db.scalars( select(MaintenanceRecord) .where(MaintenanceRecord.vehicle_id == vehicle.id) .order_by(MaintenanceRecord.occurred_at.desc()) ).all() issues = db.scalars( select(DataQualityIssue) .where(DataQualityIssue.entity_type == "vehicle", DataQualityIssue.entity_id == vehicle.id) .order_by(DataQualityIssue.detected_at.desc()) ).all() booking_by_id = {b.id: b.public_ref for b in bookings} attention_ids = _attention_vehicle_ids(db) return VehicleDetailOut( public_ref=vehicle.public_ref, make=vehicle.make, model=vehicle.model, model_year=vehicle.model_year, registration_number=vehicle.registration_number, location=vehicle.location, operational_status=vehicle.operational_status, odometer_km=vehicle.odometer_km, next_service_km=vehicle.next_service_km, active=vehicle.active, attention=vehicle.id in attention_ids or vehicle.operational_status == "blocked", bookings=[ BookingSummaryOut( public_ref=b.public_ref, customer_ref=customer_ref_by_id.get(b.customer_id, ""), vehicle_ref=vehicle.public_ref, starts_at=b.starts_at, ends_at=b.ends_at, status=b.status, ) for b in bookings ], inspections=[ InspectionOut( public_ref=i.public_ref, booking_ref=booking_by_id.get(i.booking_id, ""), type=i.type, fuel_level_percent=i.fuel_level_percent, cleanliness_ok=i.cleanliness_ok, damage_reported=i.damage_reported, technical_warning=i.technical_warning, odometer_km=i.odometer_km, completed_at=i.completed_at, ) for i in inspections ], maintenance=[ MaintenanceOut( public_ref=m.public_ref, occurred_at=m.occurred_at, odometer_km=m.odometer_km, category=m.category, summary=m.summary, ) for m in maintenance ], quality_issues=[ DataQualityIssueOut( public_ref=q.public_ref, rule_type=q.rule_type, entity_type=q.entity_type, entity_ref=vehicle.public_ref, severity=q.severity, status=q.status, evidence=q.evidence_json, detected_at=q.detected_at, resolved_at=q.resolved_at, ) for q in issues ], )