from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from starlette.routing import Mount
import numpy as np
from tensorflow import keras
import hashlib
import json
import os

class TicTacToeAI:
    def __init__(self, model_path="model/model.keras"):
        self.model_path = model_path
        self.model = None
        self.load_model()

    def load_model(self):
        """Wczytuje model z pliku"""
        if os.path.exists(self.model_path):
            self.model = keras.models.load_model(self.model_path)
            return True
        return False

    def get_move(self, board):
        """Zwraca najlepszy ruch dla danego stanu planszy"""
        if self.model is None:
            raise ValueError("Model nie został wczytany")

        board_array = np.array(board)
        predictions = self.model.predict(board_array.reshape(1, -1), verbose=0)[0]
        valid_moves = np.where(board_array == 0)[0]

        if len(valid_moves) == 0:
            raise ValueError("Brak dostępnych ruchów")

        valid_predictions = [(i, pred) for i, pred in enumerate(predictions) if i in valid_moves]
        return int(max(valid_predictions, key=lambda x: x[1])[0])


# Inicjalizacja AI
ai = TicTacToeAI()



# Ustawienie prefiksu aplikacji
app = FastAPI(root_path="/spaces/labapawel/tictactoe")

@app.on_event("startup")
async def print_routes():
    """Wyświetla wszystkie zarejestrowane trasy"""
    for route in app.routes:
        if hasattr(route, "methods"):  # Jeśli trasa obsługuje metody HTTP
            print(f"Path: {route.path}, Name: {route.name}, Methods: {route.methods}")
        elif isinstance(route, Mount):  # Jeśli to katalog statyczny
            print(f"Mounted Path: {route.path}, Name: {route.name}, App: {route.app}")
        else:  # Inny typ trasy
            print(f"Other Route Path: {route.path}, Name: {route.name}")

# Montowanie katalogu publicznego
app.mount("/static", StaticFiles(directory="public"), name="static")

@app.get("/", response_class=HTMLResponse)
async def read_root():
    try:
        with open("public/index.html", "r") as file:
            return HTMLResponse(content=file.read(), status_code=200)
    except FileNotFoundError:
        return HTMLResponse(content="Plik index.html nie został znaleziony", status_code=404)


@app.get("/status")
async def get_status():
    print("Endpoint /status został wywołany.")
    return {
        "status": "success",
        "model_loaded": True,  # lub odpowiedni warunek
        "model_path": "model/model.keras"
    }


@app.post("/savegame")
async def save_game(request: Request):
    try:
        data = await request.json()
        final_board = data.get("final_board")
        sequence = data.get("sequence")

        if not final_board or not sequence:
            raise HTTPException(status_code=400, detail="Missing required data")

        game_hash =  hash(str(final_board) + str(sequence))
        game_data = {
            "final_board": final_board,
            "sequence": sequence,
            "hash": game_hash
        }

        try:
            with open("public/games_data.json", "r") as f:
                existing_data = json.load(f)
        except (FileNotFoundError, json.JSONDecodeError):
            existing_data = []

        existing_data.append(game_data)

        with open("public/games_data.json", "w") as f:
            json.dump(existing_data, f)

        return {"status": "success", "hash": game_data["hash"]}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.post("/move")
async def get_move(request: Request):
    """
    Endpoint do wykonania ruchu AI
    """
    try:
        data = await request.json()  # Pobierz dane JSON z żądania
        board = data.get("board")


        if not board:
            raise HTTPException(status_code=400, detail="Brak planszy w żądaniu")

        if len(board) != 9 or not all(x in [0, 1, -1] for x in board):
            raise HTTPException(status_code=400, detail="Nieprawidłowe dane planszy")

        move = ai.get_move(board)

        return {"status": "success", "move": move}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))