const sqlite3 = require('sqlite3').verbose();
const fs = require('fs');
const path = require('path');

class DatabaseManager {
    constructor(dbPath = './database/gridbattle.db') {
        this.dbPath = dbPath;
        this.db = null;
    }

    async initialize() {
        console.log('Initializing Grid Battle database...');
        
        try {
            // Ensure database directory exists
            const dbDir = path.dirname(this.dbPath);
            if (!fs.existsSync(dbDir)) {
                fs.mkdirSync(dbDir, { recursive: true });
            }

            // Open database connection
            this.db = new sqlite3.Database(this.dbPath, (err) => {
                if (err) {
                    console.error('Error opening database:', err.message);
                    throw err;
                }
                console.log('Connected to SQLite database:', this.dbPath);
            });

            // Enable foreign keys
            await this.runQuery('PRAGMA foreign_keys = ON');
            
            // Load and execute schema
            const schemaPath = path.join(__dirname, 'schema.sql');
            const schema = fs.readFileSync(schemaPath, 'utf8');
            
            // Split schema into individual statements
            const statements = schema.split(';').filter(stmt => stmt.trim().length > 0);
            
            for (const statement of statements) {
                await this.runQuery(statement);
            }

            console.log('Database schema initialized successfully');
            
            // Insert default data if needed
            await this.insertDefaultData();
            
            return this.db;
        } catch (error) {
            console.error('Database initialization failed:', error);
            throw error;
        }
    }

    async insertDefaultData() {
        // Check if we need to insert any default data
        const playerCount = await this.getScalar('SELECT COUNT(*) FROM players');
        
        if (playerCount === 0) {
            console.log('Inserting default test data...');
            
            // Insert test players for development
            await this.runQuery(`
                INSERT INTO players (id, username, games_played, games_won, skill_rating)
                VALUES 
                    ('test-player-1', 'TestPlayer1', 5, 3, 1150),
                    ('test-player-2', 'TestPlayer2', 4, 1, 950),
                    ('test-player-3', 'GridMaster', 10, 8, 1300)
            `);
            
            console.log('Default test data inserted');
        }
    }

    // Promisified database operations
    runQuery(sql, params = []) {
        return new Promise((resolve, reject) => {
            this.db.run(sql, params, function(err) {
                if (err) {
                    console.error('Database query error:', err.message);
                    console.error('SQL:', sql);
                    reject(err);
                } else {
                    resolve({ lastID: this.lastID, changes: this.changes });
                }
            });
        });
    }

    getRow(sql, params = []) {
        return new Promise((resolve, reject) => {
            this.db.get(sql, params, (err, row) => {
                if (err) {
                    console.error('Database query error:', err.message);
                    reject(err);
                } else {
                    resolve(row);
                }
            });
        });
    }

    getAllRows(sql, params = []) {
        return new Promise((resolve, reject) => {
            this.db.all(sql, params, (err, rows) => {
                if (err) {
                    console.error('Database query error:', err.message);
                    reject(err);
                } else {
                    resolve(rows);
                }
            });
        });
    }

    getScalar(sql, params = []) {
        return new Promise((resolve, reject) => {
            this.db.get(sql, params, (err, row) => {
                if (err) {
                    console.error('Database query error:', err.message);
                    reject(err);
                } else {
                    // Return the first column value
                    const value = row ? Object.values(row)[0] : null;
                    resolve(value);
                }
            });
        });
    }

    async close() {
        return new Promise((resolve, reject) => {
            if (this.db) {
                this.db.close((err) => {
                    if (err) {
                        reject(err);
                    } else {
                        console.log('Database connection closed');
                        resolve();
                    }
                });
            } else {
                resolve();
            }
        });
    }

    // Helper methods for common operations
    async createPlayer(username, email = null) {
        const { v4: uuidv4 } = require('uuid');
        const playerId = uuidv4();
        
        await this.runQuery(`
            INSERT INTO players (id, username, email)
            VALUES (?, ?, ?)
        `, [playerId, username, email]);
        
        return playerId;
    }

    async createGame(gameMode = 'standard', tournamentId = null) {
        const { v4: uuidv4 } = require('uuid');
        const gameId = uuidv4();
        
        await this.runQuery(`
            INSERT INTO games (id, game_mode, tournament_id)
            VALUES (?, ?, ?)
        `, [gameId, gameMode, tournamentId]);
        
        return gameId;
    }

    async addPlayerToGame(gameId, playerId, playerNumber, spawnX, spawnY) {
        await this.runQuery(`
            INSERT INTO game_players (game_id, player_id, player_number, spawn_x, spawn_y, current_x, current_y)
            VALUES (?, ?, ?, ?, ?, ?, ?)
        `, [gameId, playerId, playerNumber, spawnX, spawnY, spawnX, spawnY]);
    }

    async logGameEvent(gameId, turnNumber, sequenceNumber, eventType, playerId, eventData = {}) {
        await this.runQuery(`
            INSERT INTO game_events (game_id, turn_number, sequence_number, event_type, player_id, 
                                   from_x, from_y, to_x, to_y, event_data)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        `, [
            gameId, turnNumber, sequenceNumber, eventType, playerId,
            eventData.from_x || null, eventData.from_y || null,
            eventData.to_x || null, eventData.to_y || null,
            JSON.stringify(eventData)
        ]);
    }

    async getGameState(gameId) {
        const game = await this.getRow('SELECT * FROM games WHERE id = ?', [gameId]);
        if (!game) return null;

        const players = await this.getAllRows(`
            SELECT gp.*, p.username 
            FROM game_players gp 
            JOIN players p ON gp.player_id = p.id 
            WHERE gp.game_id = ?
            ORDER BY gp.player_number
        `, [gameId]);

        return { game, players };
    }

    async getLeaderboard(limit = 10) {
        return await this.getAllRows(`
            SELECT * FROM leaderboard LIMIT ?
        `, [limit]);
    }

    async getGameHistory(gameId) {
        return await this.getAllRows(`
            SELECT * FROM game_events 
            WHERE game_id = ? 
            ORDER BY turn_number, sequence_number
        `, [gameId]);
    }
}

module.exports = DatabaseManager;