from __future__ import annotations

import asyncio
from typing import List

import httpx
from fastapi import FastAPI
from fastapi.testclient import TestClient

from services.api import app as api_app
from services.analytics import app as analytics_app
from services.game import app as game_app


def _install_asgi_clients() -> List[httpx.AsyncClient]:
    created: List[httpx.AsyncClient] = []

    def make_client(app: FastAPI, base_url: str) -> httpx.AsyncClient:
        client = httpx.AsyncClient(transport=httpx.ASGITransport(app=app), base_url=base_url)
        created.append(client)
        return client

    api_app.clients["game"] = make_client(game_app.app, "http://game")
    api_app.clients["analytics"] = make_client(analytics_app.app, "http://analytics")

    dummy_ai = FastAPI()

    @dummy_ai.get("/models")
    def _models():
        return {"models": []}

    @dummy_ai.post("/act")
    def _act():
        return {"action": {"type": "end_turn", "payload": {}}, "debug": {}}

    api_app.clients["ai"] = make_client(dummy_ai, "http://ai")
    return created


def _close_clients(clients: List[httpx.AsyncClient]) -> None:
    for client in clients:
        try:
            loop = asyncio.get_event_loop()
        except RuntimeError:
            asyncio.run(client.aclose())
        else:
            loop.run_until_complete(client.aclose())


def test_full_user_flow() -> None:
    with TestClient(api_app.app) as client:
        created = _install_asgi_clients()
        try:
            # Register + login
            response = client.post("/api/auth/register", json={"username": "user_flow", "password": "secret"})
            assert response.status_code == 200
            token = response.json()["token"]
            headers = {"Authorization": f"Bearer {token}"}

            # Create lobby and seat host
            response = client.post("/api/games", json={"name": "Flow", "max_players": 3}, headers=headers)
            assert response.status_code == 200
            game_id = response.json()["id"]

            response = client.post(f"/api/games/{game_id}/join", headers=headers)
            assert response.status_code == 200
            payload = response.json()
            assert payload["players"][0]["name"] == "user_flow"

            # Seat AI opponent and start the game
            for _ in range(2):
                response = client.post(
                    f"/api/games/{game_id}/add-ai",
                    json={"ai_type": "random"},
                    headers=headers,
                )
                assert response.status_code == 200

            response = client.post(f"/api/games/{game_id}/start", headers=headers)
            assert response.status_code == 200
            state = response.json()
            assert state["status"] == "running"
            assert state["game"]["phase"] == "setup_round_one"
            assert len(state["legal_actions"]) > 0
        finally:
            _close_clients(created)
