import asyncio
from contextlib import asynccontextmanager

from fastapi import FastAPI
from sqlalchemy import select

from app.config import settings
from app.database import Base, async_session, engine
from app.models import GameServer, Mode, ServerStatus
from app.queue_manager import queue_manager
from app.routers import matchmaking, ranks, servers, stats
from app.routers.servers import sweep_stale_servers


# Three fake rows so server_select.gd has a realistic-looking list before a
# real server pool exists (see README's "Not set up yet"). Only the first
# port matches DEV_SEED_SERVER_IP/PORT, so it's the only one of the three
# that's actually reachable by running a real Godot server locally — the
# other two are display-only until real servers self-register on those
# ports. player_count here is just the DB fallback; a live server overrides
# it via the UDP query responder the client probes directly (see
# spacewar/autoload/network_manager.gd).
_DEMO_PLAYER_COUNTS = [40, 20, 10]


async def _seed_demo_servers() -> None:
    async with async_session() as db:
        for i, player_count in enumerate(_DEMO_PLAYER_COUNTS):
            port = settings.dev_seed_server_port + i
            existing = (
                await db.execute(
                    select(GameServer).where(
                        GameServer.ip == settings.dev_seed_server_ip,
                        GameServer.port == port,
                        GameServer.mode == Mode.casual,
                    )
                )
            ).scalars().first()
            if existing is None:
                db.add(
                    GameServer(
                        ip=settings.dev_seed_server_ip,
                        port=port,
                        mode=Mode.casual,
                        status=ServerStatus.available,
                        player_count=player_count,
                        max_players=50,
                    )
                )
        await db.commit()


async def _run_stale_sweep_loop() -> None:
    while True:
        await asyncio.sleep(5)
        async with async_session() as db:
            await sweep_stale_servers(db)


@asynccontextmanager
async def lifespan(app: FastAPI):
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)
    await _seed_demo_servers()
    matching_task = asyncio.create_task(queue_manager.run_matching_loop())
    sweep_task = asyncio.create_task(_run_stale_sweep_loop())
    yield
    matching_task.cancel()
    sweep_task.cancel()


app = FastAPI(title="Spacewar Matchmaking API", lifespan=lifespan)

app.include_router(matchmaking.router)
app.include_router(stats.router)
app.include_router(ranks.router)
app.include_router(servers.router)


@app.get("/health")
async def health() -> dict:
    return {"status": "ok"}
