from typing import List, Optional from fastapi import APIRouter, Depends from fastapi_camelcase import CamelModel from pydantic import confloat from sqlalchemy.orm import Session from .. import scoring from ..schemas import CacheInfo, GameConfig, GeneratorInfo, ScoreMethodEnum from ..db import get_db, queries from ..point_gen import points, generator_info, reverse_geocode router = APIRouter() class Point(CamelModel): lat: confloat(ge=-90.0, le=90.0) lng: confloat(ge=-180.0, le=180.0) class ScoreCheck(CamelModel): point1: Point point2: Point score_method: Optional[ScoreMethodEnum] = None round_number: Optional[int] = None class Score(CamelModel): distance: float score: int class CacheResponse(CamelModel): caches: List[CacheInfo] class GeneratorResponse(CamelModel): generators: List[GeneratorInfo] class RecentResponse(CamelModel): recent_games: List[str] @router.get("/health") def health(): return { "status": "healthy", "version": "5.0" } @router.post("/score", response_model=Score) async def check_score(check: ScoreCheck): match check.score_method: case ScoreMethodEnum.country_distance: p1_code = await reverse_geocode(check.point1.lat, check.point1.lng) p2_code = await reverse_geocode(check.point2.lat, check.point2.lng) score_fn = scoring.score if p1_code == p2_code else scoring.score_pow score, distance = score_fn((check.point1.lat, check.point1.lng), (check.point2.lat, check.point2.lng)) case ScoreMethodEnum.country_race: p1_code = await reverse_geocode(check.point1.lat, check.point1.lng) p2_code = await reverse_geocode(check.point2.lat, check.point2.lng) score = 5000 if p1_code == p2_code else 0 distance = 0 case ScoreMethodEnum.hard: score, distance = scoring.score_hard((check.point1.lat, check.point1.lng), (check.point2.lat, check.point2.lng)) case ScoreMethodEnum.nightmare: score, distance = scoring.score_nightmare((check.point1.lat, check.point1.lng), (check.point2.lat, check.point2.lng)) case ScoreMethodEnum.ramp: score, distance = scoring.score((check.point1.lat, check.point1.lng), (check.point2.lat, check.point2.lng)) if check.round_number is not None: score *= 1 + ((check.round_number - 1) * 0.5) case ScoreMethodEnum.ramp_hard: score, distance = scoring.score_hard((check.point1.lat, check.point1.lng), (check.point2.lat, check.point2.lng)) if check.round_number is not None: score *= 1 + ((check.round_number - 1) * 0.5) case _: score, distance = scoring.score((check.point1.lat, check.point1.lng), (check.point2.lat, check.point2.lng)) return Score(distance=distance, score=score) @router.get("/caches", response_model=CacheResponse) def caches(): return CacheResponse(caches=points.get_cache_info()) @router.get("/generators", response_model=GeneratorResponse) def generators(): return GeneratorResponse(generators=generator_info) @router.get("/recent", response_model=RecentResponse) def recent(db: Session = Depends(get_db)): return RecentResponse(recent_games=[g.game_id for g in queries.get_recent_games(db, 5)])