const express = require('express');
const sqlite3 = require('sqlite3').verbose();
const bcrypt = require('bcrypt');
const cors = require('cors');
const bodyParser = require('body-parser');
const crypto = require('crypto');
const multer = require('multer'); // Add this to your dependencies
const storage = multer.memoryStorage();
const upload = multer({ storage: storage });

const app = express();
const port = 5000;

// Middleware
app.use(cors());
app.use(bodyParser.json());

// SQLite database setup
const db = new sqlite3.Database('./database.db', (err) => {
    if (err) {
        console.error(err.message);
    } else {
        console.log('Connected to SQLite database.');
    }
});

// Create users table if it doesn't exist
db.run(`CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    username TEXT UNIQUE,
    email TEXT UNIQUE,
    password TEXT
)`);

// Create games table if it doesn't exist
db.run(`CREATE TABLE IF NOT EXISTS games (
    game_id TEXT PRIMARY KEY,
    name TEXT,
    description TEXT,
    game_master_id INTEGER,
    participants TEXT
)`);


//User Part

// Registration route
app.post('/register', async (req, res) => {
    const { username, email, password } = req.body;
    console.log("Trying to Register: ", username);
    try {
        const hashedPassword = await bcrypt.hash(password, 10);
        const stmt = db.prepare('INSERT INTO users (username, email, password) VALUES (?, ?, ?)');
        stmt.run([username, email, hashedPassword], function (err) {
            if (err) {
                return res.status(400).json({ error: 'User already exists or invalid data.' });
            }
            res.status(201).json({ message: 'User registered successfully!', userId: this.lastID });
        });
        stmt.finalize();
    } catch (error) {
        res.status(500).json({ error: 'Internal server error' });
    }
});

// Login route
app.post('/login', (req, res) => {
    const { username, password } = req.body;
    db.get('SELECT * FROM users WHERE username = ?', [username], async (err, row) => {
        if (err) {
            return res.status(500).json({ error: 'Internal server error' });
        }
        if (!row || !(await bcrypt.compare(password, row.password))) {
            return res.status(400).json({ error: 'Invalid username or password.' });
        }
        res.json({ success: true, message: 'Login successful!', userId: row.id });
    });
});


// Game Part
// Fetch games for a specific user
app.get('/games/:userId', (req, res) => {
    const userId = req.params.userId;
    db.all(
        `SELECT * FROM games WHERE game_master_id = ? OR participants LIKE ?`,
        [userId, `%${userId}%`],
        (err, rows) => {
            if (err) {
                return res.status(500).json({ error: 'Internal server error' });
            }
            res.json(rows);
        }
    );
});


// Fetch game details including game master
app.get('/games/:gameId/master', (req, res) => {
    const gameId = req.params.gameId;
    db.get('SELECT * FROM games WHERE game_id = ?', [gameId], (err, row) => {
      if (err) {
        return res.status(500).json({ error: 'Internal server error' });
      }
      if (!row) {
        return res.status(404).json({ error: 'Game not found' });
      }
      // Convert game_master_id to number for consistent comparison
      res.json(row);
    });
  });

// Join Game
app.post('/joinGame/:gameId', (req, res) => {
    const gameId = req.params.gameId;
    const userId = req.body.userId;

    db.get('SELECT * FROM games WHERE game_id = ?', [gameId], (err, game) => {
        if (err) {
            return res.status(500).json({ error: 'Internal server error' });
        }
        if (!game) {
            return res.status(404).json({ error: 'Game not found' });
        }

        const participants = JSON.parse(game.participants);
        const gameMasterId = game.game_master_id;

        // Check if the user is already a participant or the game master
        if (gameMasterId === userId || participants.includes(userId)) {
            return res.status(400).json({ error: 'User is already a participant or the game master.' });
        }

        participants.push(userId);

        const stmt = db.prepare('UPDATE games SET participants = ? WHERE game_id = ?');
        stmt.run([JSON.stringify(participants), gameId], function (err) {
            if (err) {
                return res.status(400).json({ error: 'Failed to join game.' });
            }
            res.status(201).json({ message: 'User joined game successfully!', gameId: gameId });
        });
        stmt.finalize();
    });
});


// Create a new game
app.post('/games', (req, res) => {
    const { name, description, gameMasterId, participants } = req.body;
    const stmt = db.prepare('INSERT INTO games (name, description, game_master_id, participants) VALUES (?, ?, ?, ?)');
    stmt.run([name, description, gameMasterId, JSON.stringify(participants)], function (err) {
        if (err) {
            return res.status(400).json({ error: 'Failed to create game.' });
        }
        res.status(201).json({ message: 'Game created successfully!', gameId: this.lastID });
    });
    stmt.finalize();
});

app.post('/createGame', (req, res) => {
    const { name, description, gameMasterId, participants } = req.body;

    const gameId = crypto.randomBytes(4).toString('hex'); 

    const stmt = db.prepare('INSERT INTO games (game_id, name, description, game_master_id, participants) VALUES (?, ?, ?, ?, ?)');
    stmt.run([gameId, name, description, gameMasterId, JSON.stringify(participants)], function (err) {
        if (err) {
            return res.status(400).json({ error: 'Failed to create game.' });
        }
        res.status(201).json({ message: 'Game created successfully!', gameId: gameId });
    });
    stmt.finalize();
});

// Master Part
// Fetch game Participant Characters
app.get('/games/:gameId/playerchars', (req, res) => {
    const gameId = req.params.gameId;
    db.all('SELECT * FROM PlayerCharacter WHERE GameID = ?', [gameId], (err, rows) => {
        if (err) {
            return res.status(500).json({ error: 'Internal server error' });
        }
        // Process each row and convert BLOB to base64 if image exists
        const processedRows = rows.map(row => {
            if (row.Img) {
                row.Img = `data:image/jpeg;base64,${row.Img.toString('base64')}`;
            }
            return row;
        });
        res.json(processedRows);
    });
});

// Fetch game NPCs
app.get('/games/:gameId/npcs', (req, res) => {
    const gameId = req.params.gameId;
    db.all('SELECT * FROM NPC WHERE GameID = ?', [gameId], (err, row) => {
        if (err) {
            return res.status(500).json({ error: 'Internal server error' });
        }
        res.json(row);
    });
})

// Fetch game Items
app.get('/games/:gameId/items', (req, res) => {
    const gameId = req.params.gameId;
    db.all(`
        SELECT Item.*, PlayerCharacter.CharName as OwnerName 
        FROM Item 
        LEFT JOIN PlayerCharacter ON Item.OwnerID = PlayerCharacter.CharID 
        WHERE Item.GameID = ?`, 
        [gameId], 
        (err, rows) => {
            if (err) {
                return res.status(500).json({ error: 'Internal server error' });
            }
            res.json(rows);
        }
    );
})


// Player Part

// Create Player Character
app.post('/games/character/create', upload.single('image'), (req, res) => {
    const {
        charName, race, sex, age, job, description,
        maxHealth, maxMana, strength, dexterity, agility, endurance,
        gameId, playerId
    } = req.body;
    
    const imageBuffer = req.file ? req.file.buffer : null;
    
    const stmt = db.prepare(`
        INSERT INTO PlayerCharacter (
            GameID, PlayerID, CharName, Race, Sex, Age, Job,
            description, maxHealth, currentHealth, maxMana, currentMana,
            Strength, Dexterity, Agility, Endurance, Level, Gold, Img
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 0, ?)
    `);

    stmt.run([
        gameId, playerId, charName, race, sex, age, job,
        description, maxHealth, maxHealth, maxMana, maxMana,
        strength, dexterity, agility, endurance, imageBuffer
    ], function(err) {
        if (err) {
            console.error('Database error:', err);
            return res.status(500).json({ error: 'Internal server error' });
        }
        res.status(201).json({
            message: 'Character created successfully!',
            characterId: this.lastID
        });
    });
    stmt.finalize();
});

// Fetch all Player Characters of Player
app.get('/games/:userId/characters', (req, res) => {
    const userId = req.params.userId;
    db.all('SELECT * FROM PlayerCharacter WHERE PlayerId = ?', [userId], (err, rows) => {
        if (err) {
            console.error('Database error:', err);
            return res.status(500).json({ error: 'Internal server error' });
        }

        // Process each row and convert BLOB to base64 if image exists
        const processedRows = rows.map(row => {
            if (row.Img) {
                row.Img = `data:image/jpeg;base64,${row.Img.toString('base64')}`;
            }
            return row;
        });
        
        res.json(processedRows);
    });
});

// Fetch Player Character
app.get('/games/:gameId/:userId/character', (req, res) => {
    const gameId = req.params.gameId;
    const userId = req.params.userId;
    console.log(`Fetching character for gameId: ${gameId}, userId: ${userId}`); // Debug output
    db.get('SELECT * FROM PlayerCharacter WHERE GameID = ? AND PlayerID = ?', [gameId, userId], (err, row) => {
        if (err) {
            console.error('Database error:', err);
            return res.status(500).json({ error: 'Internal server error' });
        }
        if (!row) {
            return res.status(404).json({ error: 'No character found' });
        }
        
        // Convert BLOB to base64 string if image exists
        if (row.Img) {
            row.Img = `data:image/jpeg;base64,${row.Img.toString('base64')}`;
        }
        
        res.json(row);
    });
});

// Update character image
app.put('/games/:gameId/:userId/character/image', upload.single('image'), (req, res) => {
    const gameId = req.params.gameId;
    const userId = req.params.userId;
    const imageBuffer = req.file.buffer;

    const stmt = db.prepare('UPDATE PlayerCharacter SET Img = ? WHERE GameID = ? AND PlayerID = ?');
    stmt.run([imageBuffer, gameId, userId], function(err) {
        if (err) {
            console.error('Database error:', err);
            return res.status(500).json({ error: 'Internal server error' });
        }
        res.json({ message: 'Image updated successfully!' });
    });
    stmt.finalize();
});

// Update Player Character Description
app.put('/games/:gameId/:userId/character', (req, res) => {
    const gameId = req.params.gameId;
    const userId = req.params.userId;
    const { description } = req.body;

    const stmt = db.prepare('UPDATE PlayerCharacter SET description = ? WHERE GameID = ? AND PlayerID = ?');
    stmt.run([description, gameId, userId], function (err) {
        if (err) {
            console.error('Database error:', err); // Debug output
            return res.status(500).json({ error: 'Internal server error' });
        }
        res.json({ message: 'Description updated successfully!' });
    });
    stmt.finalize();
});

// Fetch Player Items
app.get('/games/:gameId/:charId/items', (req, res) => {
    const gameId = req.params.gameId;
    const charId = req.params.charId;
    console.log(`Fetching Items for GameID: ${gameId}, CharID: ${charId}`);
    db.all('SELECT * FROM Item WHERE GameID = ? AND OwnerID = ?', [gameId, charId], (err, rows) => {
        if (err) {
            console.error('Database error:', err); // Debug output
            return res.status(500).json({ error: 'Internal server error' });
        }
        console.log(rows); // Debug output
        res.json(rows);
    });
});

// Item Part
// Create Item
app.post('/games/item/create', upload.single('image'), (req, res) => {
    const {
        ItemName, Type, Art, Rarity, MaxDurability, CurrentDurability, 
        GoldValue, Abilities, GameID, AP
    } = req.body;
    
    const imageBuffer = req.file ? req.file.buffer : null;
    
    const stmt = db.prepare(`
        INSERT INTO Item (
            ItemName, Type, Art, Rarity, MaxDurability, CurrentDurability,
            GoldValue, Abilities, GameID, OwnerID, img, AP
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?)
    `);

    stmt.run([
        ItemName, Type, Art, Rarity, MaxDurability, CurrentDurability,
        GoldValue, Abilities, GameID, imageBuffer, AP
    ], function(err) {
        if (err) {
            console.error('Database error:', err);
            return res.status(500).json({ error: 'Internal server error' });
        }
        res.status(201).json({
            message: 'Item created successfully!',
            itemId: this.lastID
        });
    });
    stmt.finalize();
});

// Set Item Owner
app.post('/games/:charId/:itemId/owner', (req, res) => {
    const gameId = req.params.gameId;
    const itemId = req.params.itemId;
    const ownerId = req.body.ownerId;
    db.run('UPDATE Item SET OwnerID = ? WHERE ItemID = ?', [ownerId, gameId, itemId], function (err) {
        if (err) {
            return res.status(400).json({ error: 'Failed to update item owner.' });
        }
        res.json({ message: 'Item owner updated successfully!' });
    });
})




// Start the server
app.listen(port, () => {
    console.log(`Server running on http://localhost:${port}`);
});
