""" 🌍 Location Autocomplete API Endpoint. Provides autocomplete search for postal codes and cities from the system.geo_postal_codes table. Used by the frontend SmartLocationInput component to let users quickly find and select a zip/city pair. Schema: system.geo_postal_codes """ import logging from typing import List, Optional from fastapi import APIRouter, Depends, HTTPException, Query, status from pydantic import BaseModel, Field from sqlalchemy import select, or_ from sqlalchemy.ext.asyncio import AsyncSession from app.api.deps import get_db from app.models.identity.address import GeoPostalCode logger = logging.getLogger(__name__) router = APIRouter() class LocationAutocompleteItem(BaseModel): """Egy találat a település autocomplete keresőben.""" id: int zip_code: str city: str country_code: str = "HU" model_config = {"from_attributes": True} @router.get("/locations/autocomplete", response_model=List[LocationAutocompleteItem]) async def autocomplete_locations( q: str = Query(..., min_length=1, max_length=100, description="Keresőszó (irányítószám vagy városrészlet)"), country_code: str = Query("HU", max_length=5, description="Országkód szűrő (alapértelmezett: HU)"), limit: int = Query(15, ge=1, le=50, description="Max találatok száma"), db: AsyncSession = Depends(get_db), ): """ GET /api/v1/locations/autocomplete?q=budapest Autocomplete keresés a system.geo_postal_codes táblában. A keresés az irányítószámra (zip_code) és a város névre (city) is történik ILIKE operátorral. Példák: /api/v1/locations/autocomplete?q=1011 -> 1011 Budapest /api/v1/locations/autocomplete?q=budapest -> 1011 Budapest, 1012 Budapest, ... /api/v1/locations/autocomplete?q=101 -> 1011 Budapest, 1012 Budapest, ... /api/v1/locations/autocomplete?q=bud&country_code=AT -> 5020 Salzburg, ... """ if not q.strip(): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="A keresőszó (q) nem lehet üres.", ) try: stmt = ( select(GeoPostalCode) .where( GeoPostalCode.country_code == country_code, or_( GeoPostalCode.zip_code.ilike(f"%{q.strip()}%"), GeoPostalCode.city.ilike(f"%{q.strip()}%"), ), ) .order_by(GeoPostalCode.zip_code, GeoPostalCode.city) .limit(limit) ) result = await db.execute(stmt) items = result.scalars().all() return [ LocationAutocompleteItem( id=item.id, zip_code=item.zip_code, city=item.city, country_code=item.country_code, ) for item in items ] except Exception as e: logger.error(f"Hiba a location autocomplete során: {e}", exc_info=True) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Hiba történt a település keresés során.", )