combine these two files. code that need to be handled on the server put in index.ts and on the client in to game.ts. give only back code. really look at the code correctness

index.ts 

import { functions, httpsCallable } from './config';
import { collection, getDocs, query, where, doc, getDoc, onSnapshot } from 'firebase/firestore';
import { FirebaseError } from 'firebase/app';

// Interfaces
export interface GameSettings {
    hostName: string;
    gameName: string;
    numTeams: number;
    numRounds: number;
}

interface Player {
    id: string;
    name: string;
}

interface Team {
    id: number;
    name: string;
    members: Player[];
}

interface PublicGame {
    id: string;
    name: string;
    players: Player[];
    teams: Team[];
    maxPlayers: number;
}

interface SpotifyTrack {
    id: string;
    name: string;
    artist: string;
    album: string;
    previewUrl: string;
}

interface FullSpotifyTrack extends SpotifyTrack {
    duration_ms: number;
    explicit: boolean;
    popularity: number;
    albumArt: string;
}

interface TeamScore {
    name: string;
    totalPoints: number;
    roundPoints: number;
}

interface TopSong {
    title: string;
    artist: string;
    points: number;
}

// Client-Side Functions

// Function to Create a Game via Cloud Function
export const createGame = async (gameSettings: GameSettings): Promise<string> => {
    const createGameFunction = httpsCallable<{ hostName: string, gameName: string, numTeams: number, numRounds: number }, { gameId: string }>(functions, 'createGame');
    try {
        const result = await createGameFunction(gameSettings);
        return result.data.gameId;
    } catch (error) {
        console.error('Error creating game:', error);
        throw error;
    }
};

// Function to Join a Game via Cloud Function
export const joinGame = async (gameId: string, playerName: string): Promise<boolean> => {
    const joinGameFunction = httpsCallable<{ gameId: string, playerName: string }, { success: boolean, message: string }>(functions, 'joinGame');
    try {
        const result = await joinGameFunction({ gameId, playerName });
        return result.data.success;
    } catch (error) {
        console.error('Error joining game:', error);
        throw error;
    }
};

// Function to Fetch Public Games (Read Operation)
export const fetchPublicGames = async (): Promise<PublicGame[]> => {
    const q = query(collection(admin.firestore(), 'games'), where('status', '==', 'lobby'));
    const querySnapshot = await getDocs(q);
    return querySnapshot.docs.map(docSnap => ({
        id: docSnap.id,
        name: docSnap.data().gameName,
        players: docSnap.data().players,
        teams: docSnap.data().teams,
        maxPlayers: docSnap.data().maxPlayers
    }));
};

// Function to Start a Game via Cloud Function
export const startGame = async (gameId: string): Promise<{ success: boolean, message: string }> => {
    const startGameFunction = httpsCallable<{ gameId: string }, { success: boolean, message: string }>(functions, 'startGame');
    try {
        const result = await startGameFunction({ gameId });
        return result.data;
    } catch (error) {
        console.error('Error starting game:', error);
        throw error;
    }
};

// Function to Submit a Song via Cloud Function
export const submitSong = async (gameId: string, teamId: number, songId: string): Promise<{ success: boolean, message: string }> => {
    const submitSongFunction = httpsCallable<{ gameId: string, teamId: number, songId: string }, { success: boolean, message: string }>(functions, 'submitSong');
    try {
        const result = await submitSongFunction({ gameId, teamId, songId });
        return result.data;
    } catch (error) {
        console.error('Error submitting song:', error);
        throw error;
    }
};

// Function to Vote for a Song via Cloud Function
export const voteForSong = async (gameId: string, roundId: string, songId: string): Promise<{ success: boolean, message: string }> => {
    const voteForSongFunction = httpsCallable<{ gameId: string, roundId: string, songId: string }, { success: boolean, message: string }>(functions, 'voteForSong');
    try {
        const result = await voteForSongFunction({ gameId, roundId, songId });
        return result.data;
    } catch (error) {
        console.error('Error voting for song:', error);
        throw error;
    }
};

// Function to Get Game Data (Read Operation)
export const getGameData = async (gameId: string): Promise<any> => {
    const gameRef = doc(admin.firestore(), 'games', gameId);
    const gameSnap = await getDoc(gameRef);
    if (gameSnap.exists()) {
        return { id: gameSnap.id, ...gameSnap.data() };
    }
    return null;
};

// Function to Update Joker Status via Cloud Function
export const updateJokerStatus = async (gameId: string, used: boolean): Promise<{ success: boolean, message: string }> => {
    const updateJokerStatusFunction = httpsCallable<{ gameId: string, used: boolean }, { success: boolean, message: string }>(functions, 'updateJokerStatus');
    try {
        const result = await updateJokerStatusFunction({ gameId, used });
        return result.data;
    } catch (error) {
        console.error('Error updating joker status:', error);
        throw error;
    }
};

// Function to Add a Player to a Team via Cloud Function
export const addPlayerToTeam = async (gameId: string, playerName: string, teamId: number): Promise<{ success: boolean, message: string }> => {
    const addPlayerToTeamFunction = httpsCallable<{ gameId: string, playerName: string, teamId: number }, { success: boolean, message: string }>(functions, 'addPlayerToTeam');
    try {
        const result = await addPlayerToTeamFunction({ gameId, playerName, teamId });
        return result.data;
    } catch (error) {
        console.error('Error adding player to team:', error);
        throw error;
    }
};

// Function to Remove a Player from a Team via Cloud Function
export const removePlayerFromTeam = async (gameId: string, teamId: number, playerId: string): Promise<{ success: boolean, message: string }> => {
    const removePlayerFromTeamFunction = httpsCallable<{ gameId: string, teamId: number, playerId: string }, { success: boolean, message: string }>(functions, 'removePlayerFromTeam');
    try {
        const result = await removePlayerFromTeamFunction({ gameId, teamId, playerId });
        return result.data;
    } catch (error) {
        console.error('Error removing player from team:', error);
        throw error;
    }
};

// Function to Start a New Round via Cloud Function
export const startNewRound = async (gameId: string): Promise<{ success: boolean, message: string }> => {
    const startNewRoundFunction = httpsCallable<{ gameId: string }, { success: boolean, message: string }>(functions, 'startNewRound');
    try {
        const result = await startNewRoundFunction({ gameId });
        return result.data;
    } catch (error) {
        console.error('Error starting new round:', error);
        throw error;
    }
};

// Function to Get Game Songs via Cloud Function
export const getGameSongs = async (gameId: string): Promise<FullSpotifyTrack[]> => {
    const getGameSongsFunction = httpsCallable<{ gameId: string }, FullSpotifyTrack[]>(functions, 'getGameSongs');
    try {
        const result = await getGameSongsFunction({ gameId });
        return result.data;
    } catch (error) {
        console.error('Error getting game songs:', error);
        throw error;
    }
};

// Function to Search Tracks via Cloud Function
export const searchTracks = async (query: string, limit: number = 5): Promise<SpotifyTrack[]> => {
    const searchTracksFunction = httpsCallable<{ query: string, limit: number }, SpotifyTrack[]>(functions, 'searchSpotifyTracks');
    try {
        const result = await searchTracksFunction({ query, limit });
        return result.data;
    } catch (error) {
        console.error('Error searching tracks:', error);
        throw error;
    }
};

// Function to Get Suggested Songs via Cloud Function
export const getSuggestedSongs = async (gameId: string): Promise<SpotifyTrack[]> => {
    const getSuggestedSongsFunction = httpsCallable<{ gameId: string }, SpotifyTrack[]>(functions, 'getSuggestedSongs');
    try {
        const result = await getSuggestedSongsFunction({ gameId });
        return result.data;
    } catch (error) {
        console.error('Error getting suggested songs:', error);
        throw error;
    }
};

// Function to Get Current Round Info (Read Operation)
export const getCurrentRoundInfo = async (gameId: string): Promise<{ roundNumber: number, roundName: string } | null> => {
    const gameRef = doc(admin.firestore(), 'games', gameId);
    const gameSnap = await getDoc(gameRef);

    if (gameSnap.exists()) {
        const gameData = gameSnap.data();
        const currentRound = gameData.currentRound;
        const roundRef = doc(admin.firestore(), games / ${ gameId } / rounds / round${ currentRound });
        const roundSnap = await getDoc(roundRef);

        if (roundSnap.exists()) {
            const roundData = roundSnap.data();
            return {
                roundNumber: roundData.roundNumber,
                roundName: roundData.roundName
            };
        }
    }

    return null;
};

// Function to Listen to Game Updates
export const listenToGameUpdates = (gameId: string, callback: (game: any) => void): (() => void) => {
    const gameRef = doc(admin.firestore(), 'games', gameId);
    return onSnapshot(gameRef, (docSnap) => {
        if (docSnap.exists()) {
            callback({ id: docSnap.id, ...docSnap.data() });
        }
    });
};

// Function to Get Game Scores via Cloud Function
export const getGameScores = async (gameId: string): Promise<{ teamScores: TeamScore[], topSongs: TopSong[] }> => {
    const getGameScoresFunction = httpsCallable<{ gameId: string }, { teamScores: TeamScore[], topSongs: TopSong[] }>(functions, 'getGameScores');
    try {
        const result = await getGameScoresFunction({ gameId });
        return result.data;
    } catch (error) {
        console.error('Error getting game scores:', error);
        throw error;
    }
};

// Function to Calculate Round Scores via Cloud Function
export const calculateRoundScores = async (gameId: string): Promise<{ success: boolean }> => {
    const calculateRoundScoresFunction = httpsCallable<{ gameId: string }, { success: boolean }>(functions, 'calculateRoundScores');
    try {
        const result = await calculateRoundScoresFunction({ gameId });
        return result.data;
    } catch (error) {
        console.error('Error calculating round scores:', error);
        throw error;
    }
};

index.ts

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import axios from 'axios';
import * as qs from 'qs';

admin.initializeApp();

const SPOTIFY_CLIENT_ID = process.env.SPOTIFY_CLIENT_ID || "ddb35d8c5a3148869c05b32ff64c057c";
const SPOTIFY_CLIENT_SECRET = process.env.SPOTIFY_CLIENT_SECRET || "474ff3197098498296cb6adacd8633b7";
const SPOTIFY_REDIRECT_URI = process.env.SPOTIFY_REDIRECT_URI || "http://localhost:5173/spotify-callback";

if (!SPOTIFY_CLIENT_ID || !SPOTIFY_CLIENT_SECRET || !SPOTIFY_REDIRECT_URI) {
    throw new Error('Spotify credentials are not properly configured in environment variables.');
}

interface StartGameData {
    gameId: string;
}

interface SpotifyTokenResponse {
    access_token: string;
    token_type: string;
    expires_in: number;
    refresh_token?: string;
    scope: string;
}

export const startGame = functions.https.onCall(async (data: StartGameData, context: functions.https.CallableContext) => {
    if (!context.auth) {
        throw new functions.https.HttpsError('unauthenticated', 'The function must be called while authenticated.');
    }

    const { gameId } = data;

    try {
        await admin.firestore().doc(`games/${gameId}`).update({
            status: 'in_progress',
            startedAt: admin.firestore.FieldValue.serverTimestamp()
        });
        return { success: true, message: 'Game started successfully' };
    } catch (error) {
        console.error('Error starting game:', error);
        throw new functions.https.HttpsError('internal', 'Failed to start the game');
    }
});

// Modify getSpotifyToken to be a regular async function instead of an HTTPS callable
async function getSpotifyTokenInternal(): Promise<string> {
    try {
        const response = await axios.post<SpotifyTokenResponse>(
            'https://accounts.spotify.com/api/token',
            qs.stringify({ grant_type: 'client_credentials' }),
            {
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded',
                    'Authorization': 'Basic ' + Buffer.from(`${SPOTIFY_CLIENT_ID}:${SPOTIFY_CLIENT_SECRET}`).toString('base64')
                }
            }
        );

        return response.data.access_token;
    } catch (error) {
        console.error('Error getting Spotify token:', error);
        throw new Error('Failed to get Spotify token');
    }
}

// Keep the original getSpotifyToken as an HTTPS callable for client-side use
export const getSpotifyToken = functions.https.onCall(async (data: unknown, context: functions.https.CallableContext) => {
    try {
        const accessToken = await getSpotifyTokenInternal();
        return { accessToken };
    } catch (error) {
        console.error('Error in getSpotifyToken:', error);
        throw new functions.https.HttpsError('internal', 'Failed to get Spotify token');
    }
});

interface ExchangeSpotifyTokenData {
    code: string;
}

export const exchangeSpotifyToken = functions.https.onCall(async (data: ExchangeSpotifyTokenData, context: functions.https.CallableContext) => {
    if (!context.auth) {
        throw new functions.https.HttpsError('unauthenticated', 'The function must be called while authenticated.');
    }

    const { code } = data;

    try {
        const response = await axios.post<SpotifyTokenResponse>(
            'https://accounts.spotify.com/api/token',
            qs.stringify({
                grant_type: 'authorization_code',
                code,
                redirect_uri: SPOTIFY_REDIRECT_URI,
                client_id: SPOTIFY_CLIENT_ID,
                client_secret: SPOTIFY_CLIENT_SECRET,
            }),
            {
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded',
                }
            }
        );

        return {
            access_token: response.data.access_token,
            refresh_token: response.data.refresh_token,
            expires_in: response.data.expires_in,
        };
    } catch (error) {
        console.error('Error exchanging Spotify token:', error);
        throw new functions.https.HttpsError('internal', 'Failed to exchange Spotify token');
    }
});

export const searchSpotifyTracks = functions.https.onCall(async (data: { query: string, limit?: number }, context) => {

    const { query, limit = 10 } = data;

    try {
        const token = await getSpotifyTokenInternal();

        const response = await axios.get('https://api.spotify.com/v1/search', {
            params: {
                q: query,
                type: 'track',
                limit: limit
            },
            headers: {
                'Authorization': `Bearer ${token}`
            }
        });

        return response.data.tracks.items.map((track: any) => ({
            id: track.id,
            name: track.name,
            artist: track.artists[0].name,
            album: track.album.name,
            previewUrl: track.preview_url
        }));
    } catch (error) {
        console.error('Error searching Spotify tracks:', error);
        throw new functions.https.HttpsError('internal', 'Failed to search Spotify tracks');
    }
});

export const getSpotifyTracks = functions.https.onCall(async (data: { ids: string[] }, context) => {
    if (!context.auth) {
        throw new functions.https.HttpsError('unauthenticated', 'The function must be called while authenticated.');
    }

    const { ids } = data;

    try {
        const token = await getSpotifyTokenInternal();

        const response = await axios.get(`https://api.spotify.com/v1/tracks?ids=${ids.join(',')}`, {
            headers: {
                'Authorization': `Bearer ${token}`
            }
        });

        return response.data.tracks.map(track => ({
            id: track.id,
            name: track.name,
            artist: track.artists[0].name,
            album: track.album.name,
            previewUrl: track.preview_url,
            duration_ms: track.duration_ms,
            explicit: track.explicit,
            popularity: track.popularity,
            albumArt: track.album.images[0]?.url,
            // Add any other properties you need
        }));
    } catch (error) {
        console.error('Error getting Spotify tracks:', error);
        throw new functions.https.HttpsError('internal', 'Failed to get Spotify tracks');
    }
});