import { useEffect, useState, useCallback, useRef } from "react";
import { useWebSocket } from "./useWebSocket";
import { useNavigate } from "react-router-dom";

interface PlayerInfo {
    discordId: string;
    username: string;
}

interface GameRoomState {
    gameState: unknown;
    players: PlayerInfo[];
    spectators: PlayerInfo[];
    roomStatus: "connecting" | "waiting" | "playing" | "finished" | "not_found";
    isSpectator: boolean;
    gameOver: { winner: string | null; reason: string } | null;
    error: string | null;
    sessionReplaced: boolean;
}

export function useGameRoom(roomId: string, userId: string, role?: string, preferAs: "player" | "spectator" = "player") {
    const { send, subscribe, connected } = useWebSocket();
    const navigate = useNavigate();
    const navigateRef = useRef(navigate);
    useEffect(() => {
        navigateRef.current = navigate;
    }, [navigate]);

    const [state, setState] = useState<GameRoomState>({
        gameState: null,
        players: [],
        spectators: [],
        roomStatus: "connecting",
        isSpectator: false,
        gameOver: null,
        error: null,
        sessionReplaced: false,
    });

    useEffect(() => {
        if (!connected) return;

        send({ type: "JOIN_ROOM", roomId, preferAs, role: role ?? "player" });

        const unsubscribe = subscribe((msg: any) => {
            if (msg.roomId && msg.roomId !== roomId) return;

            switch (msg.type) {
                case "JOIN_RESULT":
                    setState(prev => ({
                        ...prev,
                        isSpectator: msg.joinedAs === "spectator",
                        roomStatus: msg.roomStatus,
                        players: msg.players ?? prev.players,
                        spectators: msg.spectators ?? prev.spectators,
                        gameState: msg.state !== undefined ? msg.state : prev.gameState,
                    }));
                    break;

                case "GAME_STATE":
                    setState(prev => ({
                        ...prev,
                        gameState: msg.state,
                        roomStatus: prev.roomStatus === "finished" ? "finished" : "playing",
                    }));
                    break;

                case "GAME_STARTED":
                    setState(prev => ({ ...prev, gameState: msg.state, roomStatus: "playing" }));
                    break;

                case "GAME_UPDATE":
                    setState(prev => ({ ...prev, gameState: msg.state }));
                    break;

                case "PLAYER_JOINED":
                    setState(prev => {
                        if (msg.joinedAs === "spectator") {
                            const isMe = msg.player.discordId === userId;
                            return {
                                ...prev,
                                spectators: [...prev.spectators.filter(s => s.discordId !== msg.player.discordId), msg.player],
                                isSpectator: isMe || prev.isSpectator,
                                roomStatus: prev.roomStatus === "connecting" ? "waiting" : prev.roomStatus,
                            };
                        }

                        const isMe = msg.player.discordId === userId;
                        return {
                            ...prev,
                            players: [...prev.players.filter(p => p.discordId !== msg.player.discordId), msg.player],
                            isSpectator: isMe ? false : prev.isSpectator,
                            roomStatus: prev.roomStatus === "connecting" ? "waiting" : prev.roomStatus,
                        };
                    });
                    break;

                case "PLAYER_LEFT":
                    setState(prev => ({
                        ...prev,
                        players: prev.players.filter(p => p.discordId !== msg.playerId),
                        spectators: prev.spectators.filter(s => s.discordId !== msg.playerId),
                    }));
                    break;

                case "GAME_ENDED":
                    setState(prev => ({
                        ...prev,
                        roomStatus: "finished",
                        gameOver: { winner: msg.winner, reason: msg.reason },
                    }));
                    break;

                case "SESSION_REPLACED":
                    setState(prev => ({ ...prev, sessionReplaced: true }));
                    break;

                case "ERROR":
                    if (msg.message === "Room not found") {
                        setState(prev => ({ ...prev, roomStatus: "not_found" }));
                        setTimeout(() => navigateRef.current("/games"), 2000);
                    } else {
                        setState(prev => ({ ...prev, error: msg.message }));
                    }
                    break;
            }
        });

        return () => {
            send({ type: "LEAVE_ROOM", roomId });
            unsubscribe();
        };
    }, [roomId, connected, userId, send, subscribe]);

    const sendAction = useCallback((action: unknown) => {
        send({ type: "GAME_ACTION", roomId, action });
        setState(prev => ({ ...prev, error: null }));
    }, [roomId, send]);

    const leaveRoom = useCallback(() => {
        send({ type: "LEAVE_ROOM", roomId });
    }, [roomId, send]);

    const rejoin = useCallback(() => {
        send({ type: "JOIN_ROOM", roomId, preferAs, role: role ?? "player" });
        setState(prev => ({ ...prev, sessionReplaced: false }));
    }, [roomId, preferAs, role, send]);

    const fillRoom = useCallback(() => {
        send({ type: "FILL_ROOM", roomId });
    }, [roomId, send]);

    return { ...state, sendAction, leaveRoom, rejoin, fillRoom };
}
