from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List, Optional
import httpx
import os
from dotenv import load_dotenv

# Загрузка переменных окружения из .env файла
load_dotenv()

app = FastAPI(title="OSRM API Wrapper")

# --- Модели для запросов и ответов ---

# Входная модель для обоих эндпоинтов: массив точек
class PointsRequest(BaseModel):
    points: List[List[float]]  # Формат: [[lat, lon], [lat, lon], ...]

# Модель ответа для /table
class TableResponse(BaseModel):
    distances: List[List[float]]
    durations: List[List[float]]

# Модель для одного шага в маршруте (для /route)
class RouteStep(BaseModel):
    location: List[float] # [lon, lat]
    distance: float
    type: str
    modifier: Optional[str] = ""
    name: str

# Модель ответа для /route
class RouteResponse(BaseModel):
    steps: List[RouteStep]

# --- Конфигурация ---

# Чтение URL OSRM из переменной окружения
OSRM_BASE_URL = os.getenv("OSRM_URL")

if not OSRM_BASE_URL:
    raise RuntimeError("Переменная окружения OSRM_URL не установлена.")

# --- Эндпоинты ---

@app.post("/table", response_model=TableResponse)
async def table(request: PointsRequest):
    """
    Принимает список координат и возвращает матрицы расстояний и времени в пути между ними.
    """
    if len(request.points) < 2:
        raise HTTPException(status_code=400, detail="Нужно минимум 2 точки")

    # OSRM ожидает формат lon,lat
    coords = ";".join(f"{lon},{lat}" for lat, lon in request.points)
    
    # Эндпоинт для Table service
    url = f"{OSRM_BASE_URL}/table/v1/foot/{coords}?annotations=duration,distance"
    print(f"Запрос к OSRM: {url}")

    async with httpx.AsyncClient() as client:
        try:
            resp = await client.get(url, timeout=10)
            resp.raise_for_status()
        except httpx.RequestError as exc:
            raise HTTPException(status_code=500, detail=f"Ошибка запроса к OSRM: {exc.request.url!r} - {exc}")
        except httpx.HTTPStatusError as exc:
            raise HTTPException(status_code=500, detail=f"OSRM вернул ошибку {exc.response.status_code}: {exc.response.text}")

        data = resp.json()

    distances = data.get("distances")
    durations = data.get("durations")

    if distances is None or durations is None:
        raise HTTPException(status_code=500, detail="OSRM вернул некорректный ответ")

    return TableResponse(distances=distances, durations=durations)


@app.post("/route", response_model=RouteResponse)
async def route(request: PointsRequest):
    """
    Принимает две точки (начальную и конечную) и возвращает пошаговый маршрут.
    """
    if len(request.points) != 2:
        raise HTTPException(status_code=400, detail="Для маршрута нужно ровно 2 точки")

    coords = ";".join(f"{lon},{lat}" for lat, lon in request.points)
    
    # Эндпоинт для Route service с параметром steps=true
    url = f"{OSRM_BASE_URL}/route/v1/foot/{coords}?steps=true"
    print(f"Запрос к OSRM: {url}")

    async with httpx.AsyncClient() as client:
        try:
            resp = await client.get(url, timeout=10)
            resp.raise_for_status()
        except httpx.RequestError as exc:
            raise HTTPException(status_code=500, detail=f"Ошибка запроса к OSRM: {exc.request.url!r} - {exc}")
        except httpx.HTTPStatusError as exc:
            raise HTTPException(status_code=500, detail=f"OSRM вернул ошибку {exc.response.status_code}: {exc.response.text}")
        
        data = resp.json()

    if "routes" not in data or len(data["routes"]) == 0:
        raise HTTPException(status_code=500, detail="OSRM не вернул маршруты")

    # Извлекаем шаги из ответа
    raw_steps = data["routes"][0]["legs"][0]["steps"]
    
    formatted_steps = []
    for step in raw_steps:
        maneuver = step["maneuver"]
        formatted_steps.append(
            RouteStep(
                location=[maneuver["location"][1], maneuver["location"][0]],
                distance=step["distance"],
                type=maneuver["type"],
                modifier=maneuver.get("modifier"),
                name=step.get("name", "")
            )
        )

    return RouteResponse(steps=formatted_steps)

