import asyncpg
from fastapi import FastAPI, HTTPException, APIRouter
from pydantic import BaseModel
from typing import Union
import uvicorn
import asyncio
import traceback

app = FastAPI(
    title="Game API",
    docs_url="/game-api/docs",
    redoc_url="/game-api/redoc",
    openapi_url="/game-api/openapi.json"
)

# Создаём APIRouter с префиксом /game-api
router = APIRouter(prefix="/game-api")

# Глобальная переменная для пула соединений
db_pool: asyncpg.pool.Pool | None = None


async def init_db():
    global db_pool
    if db_pool is None:
        db_pool = await asyncpg.create_pool(
            host="localhost",
            port="5432",
            database="pautina-games",
            user="pautina",
            password="fI7hP7zA2tuY4oI8yT1k",
            min_size=10,
            max_size=10
        )
        print("Пул соединений с базой данных успешно инициализирован.")


async def close_db():
    """
    Закрывает пул соединений с PostgreSQL.
    """
    global db_pool
    if db_pool:
        await db_pool.close()
        print("Пул соединений с базой данных закрыт.")


class SaveRequest(BaseModel):
    user_id: str  # Идентификатор пользователя (Telegram, Yandex, UUID из куки и т.д.)
    name: str  # Имя значения
    value: Union[str, int, dict]  # Сохраняемое значение (число, строка или словарь)


@router.post("/save")
async def save_value(payload: SaveRequest):
    await init_db()
    """
    Сохранить значение в базе данных по user_id и name.
    """
    query = """
    INSERT INTO user_values (user_id, value_name, user_value)
    VALUES ($1, $2, $3)
    ON CONFLICT (user_id, value_name)
    DO UPDATE SET user_value = EXCLUDED.user_value;
    """
    try:
        global db_pool
        await db_pool.execute(query, payload.user_id, payload.name, payload.value)
        return {"status": "ok", "message": "Значение сохранено"}
    except Exception:
        traceback.print_exc()
        raise HTTPException(status_code=500, detail="Ошибка при сохранении значения.")


@router.get("/load")
async def load_value(user_id: str, name: str):
    await init_db()
    """
    Получить ранее сохранённое значение по user_id и name.
    """
    query = """
    SELECT user_value FROM user_values
    WHERE user_id = $1 AND value_name = $2;
    """
    try:
        global db_pool
        record = await db_pool.fetchrow(query, user_id, name)
        if record:
            return {"status": "ok", "value": record["user_value"]}
        else:
            return {"status": "ok", "value": None}
    except Exception:
        traceback.print_exc()
        raise HTTPException(status_code=500, detail="Ошибка при загрузке значения.")


@router.post("/coloring_book/{picture_id}")
async def update_coloring_book(picture_id: str):
    await init_db()
    query = """
    INSERT INTO coloring_book (picture_id, times_used)
    VALUES ($1, 1)
    ON CONFLICT (picture_id)
    DO UPDATE SET times_used = coloring_book.times_used + 1;
    """
    try:
        global db_pool
        await db_pool.execute(query, picture_id)
        return {"status": "ok", "message": "Запись успешно обновлена"}
    except Exception:
        traceback.print_exc()
        raise HTTPException(status_code=500, detail="Ошибка при обновлении записи coloring_book.")


@router.get("/coloring_book_pictures")
async def get_sorted_coloring_book_json():
    """
    Возвращает отсортированный по убыванию times_used список записей из coloring_book в формате JSON.
    """
    await init_db()
    query = """
    SELECT picture_id, times_used
    FROM coloring_book
    ORDER BY times_used DESC;
    """
    try:
        global db_pool
        records = await db_pool.fetch(query)

        # Преобразуем записи в список словарей
        result = [
            {"picture_id": record["picture_id"], "times_used": record["times_used"]}
            for record in records
        ]
        return result
    except Exception:
        traceback.print_exc()
        raise HTTPException(
            status_code=500, detail="Ошибка при получении записей из coloring_book."
        )


@router.get("/")
async def root():
    """
    Корневой маршрут для /game-api/
    """
    return {"message": "Game API"}


# Включаем маршруты в основное приложение
app.include_router(router)


async def run_app():
    """
    Запускает FastAPI приложение с инициализацией и закрытием базы данных.
    """
    try:
        config = uvicorn.Config(app, host="0.0.0.0", port=8000, log_level="info")
        server = uvicorn.Server(config)
        await server.serve()
    except Exception:
        traceback.print_exc()
    finally:
        await close_db()


def main():
    """
    Основная функция, запускающая сервер в цикле с обработкой исключений.
    """
    while True:
        try:
            asyncio.run(run_app())
        except Exception:
            traceback.print_exc()
            print("Произошла ошибка. Перезапуск сервера через 5 секунд...")
            asyncio.run(asyncio.sleep(5))


if __name__ == "__main__":
    main()
