const express = require('express');
const http = require('http');
const socketIO = require('socket.io');
const cors = require('cors');
const path = require('path');
const { initializeDatabase, db, supabase } = require('./database');
const GameManager = require('./gameManager');

const app = express();
const server = http.createServer(app);
const io = socketIO(server, {
    cors: {
        origin: "*",
        methods: ["GET", "POST"]
    }
});

const PORT = process.env.PORT || 3000;

// Middleware
app.use(cors());
app.use(express.json());
app.use(express.static(path.join(__dirname)));

// Serve index.html for root route
app.get('/', (req, res) => {
    res.sendFile(path.join(__dirname, 'index.html'));
});

// Database health check endpoint with detailed diagnostics
app.get('/api/db-status', async (req, res) => {
    const startTime = Date.now();
    const dbConfig = require('./db.config.js');
    
    let status = {
        connected: false,
        latency: 0,
        writeCapable: false,
        timestamp: new Date().toISOString(),
        error: null,
        // Additional diagnostic info for testing phase
        supabaseUrl: dbConfig.supabaseUrl || 'unknown',
        database: 'Supabase PostgreSQL',
        connectionType: 'Supabase Client'
    };

    try {
        console.log(`[DB-STATUS] Testing Supabase connection to ${status.supabaseUrl}...`);
        
        // Test connection with a simple query
        const { data, error } = await supabase
            .from('players')
            .select('id')
            .limit(1);
        
        const latency = Date.now() - startTime;
        
        if (!error || error.code === 'PGRST116') { // PGRST116 = no rows found (table exists but empty)
            status.connected = true;
            status.latency = latency;
            console.log(`[DB-STATUS] ✅ Connection successful (${latency}ms)`);

            // Test write capability
            try {
                console.log(`[DB-STATUS] Testing write capability...`);
                
                // Try to insert a test record
                const testUsername = `_test_${Date.now()}`;
                const { data: insertData, error: insertError } = await supabase
                    .from('players')
                    .insert([{ username: testUsername }])
                    .select('id')
                    .single();
                
                if (!insertError && insertData) {
                    // Clean up test record
                    await supabase
                        .from('players')
                        .delete()
                        .eq('id', insertData.id);
                    
                    status.writeCapable = true;
                    console.log(`[DB-STATUS] ✅ Write test successful`);
                } else {
                    throw insertError;
                }
            } catch (writeError) {
                console.error(`[DB-STATUS] ❌ Write test failed:`, writeError.message);
                status.writeCapable = false;
                status.error = `Write test failed: ${writeError.message}`;
            }
        } else {
            throw error;
        }
    } catch (error) {
        console.error(`[DB-STATUS] ❌ Connection failed:`, error.message);
        console.error(`[DB-STATUS] Error details:`, error);
        
        status.connected = false;
        status.latency = Date.now() - startTime;
        
        // Provide more detailed error messages
        let errorMessage = error.message;
        if (error.code === '42P01') {
            errorMessage = `Table 'players' does not exist. Please run the SQL schema in Supabase SQL Editor.`;
        } else if (error.message && error.message.includes('Invalid API key')) {
            errorMessage = `Invalid Supabase API key. Check your db.config.js file.`;
        } else if (error.message && error.message.includes('fetch')) {
            errorMessage = `Cannot reach Supabase. Check your supabaseUrl in db.config.js.`;
        }
        
        status.error = errorMessage;
    }

    res.json(status);
});

// Initialize game manager
const gameManager = new GameManager(io, db);

// Socket.io connection handling
io.on('connection', (socket) => {
    console.log(`✅ Player connected: ${socket.id}`);
    
    // Player registration
    socket.on('register_player', async (data) => {
        console.log('📝 Registration request from', socket.id, 'username:', data.username);
        const result = await gameManager.registerPlayer(socket, data.username);
        console.log('📝 Registration result:', result);
        socket.emit('registration_result', result);
    });
    
    // Send challenge
    socket.on('send_challenge', async (data) => {
        const result = await gameManager.sendChallenge(socket, data.targetUsername, data.boardSize);
        socket.emit('challenge_result', result);
    });
    
    // Accept challenge
    socket.on('accept_challenge', async (data) => {
        const result = await gameManager.acceptChallenge(socket, data.challengeId);
        if (result.success) {
            socket.emit('challenge_accepted', result);
        } else {
            socket.emit('challenge_error', result);
        }
    });
    
    // Decline challenge
    socket.on('decline_challenge', (data) => {
        gameManager.declineChallenge(socket, data.challengeId);
    });
    
    // Make move
    socket.on('make_move', async (data) => {
        const result = await gameManager.handleMove(socket, data);
        socket.emit('move_result', result);
    });
    
    // Heartbeat to keep session alive
    socket.on('heartbeat', async () => {
        await gameManager.heartbeat(socket);
    });
    
    // Request active players
    socket.on('request_active_players', async () => {
        const activePlayers = await db.getActivePlayers();
        socket.emit('active_players_update', activePlayers);
    });
    
    // Disconnect
    socket.on('disconnect', async () => {
        console.log(`❌ Player disconnected: ${socket.id}`);
        await gameManager.handleDisconnect(socket);
    });
});

// Cleanup stale sessions periodically
setInterval(async () => {
    await db.cleanupStaleSessions();
}, 60000); // Every minute

// Error handling
process.on('unhandledRejection', (error) => {
    console.error('Unhandled promise rejection:', error);
});

// Initialize database and start server
async function startServer() {
    try {
        await initializeDatabase();
        
        server.listen(PORT, () => {
            console.log('');
            console.log('═══════════════════════════════════════════════════');
            console.log('🎮 Connect-5 Multiplayer Server');
            console.log('═══════════════════════════════════════════════════');
            console.log(`🌐 Server running on port ${PORT}`);
            console.log(`📡 WebSocket server ready`);
            console.log(`🗄️  Database connected`);
            console.log('');
            console.log(`🎯 Open your browser to: http://localhost:${PORT}`);
            console.log('═══════════════════════════════════════════════════');
            console.log('');
        });
    } catch (error) {
        console.error('Failed to start server:', error);
        process.exit(1);
    }
}

startServer();
