import express from 'express';
import cors from 'cors';
import dotenv from 'dotenv';
import db from './db.js';
import { AddressEntry, User } from './types.js';

dotenv.config();

const app = express();
const PORT = process.env.PORT || 3001;

app.use(cors());
app.use(express.json());

// Middleware to validate session token
async function validateSession(req: express.Request, res: express.Response, next: express.NextFunction) {
  const token = req.headers.authorization?.replace('Bearer ', '') || req.query.token as string;

  if (!token) {
    return res.status(401).json({ error: 'Session token required' });
  }

  try {
    const [sessions] = await db.query<any[]>(
      'SELECT * FROM player_sessions WHERE token = ? AND expires_at > ?',
      [token, Math.floor(Date.now() / 1000)]
    );

    if (sessions.length === 0) {
      return res.status(401).json({ error: 'Invalid or expired session' });
    }

    req.body.sessionUserId = sessions[0].user_id;
    next();
  } catch (error) {
    console.error('Session validation error:', error);
    res.status(500).json({ error: 'Session validation failed' });
  }
}

// Get user info by session token
app.get('/api/user', validateSession, async (req, res) => {
  try {
    const userId = req.body.sessionUserId;
    const [users] = await db.query<User[]>(
      'SELECT user_id, username, display_name FROM player_common WHERE user_id = ?',
      [userId]
    );

    if (users.length === 0) {
      return res.status(404).json({ error: 'User not found' });
    }

    res.json(users[0]);
  } catch (error) {
    console.error('Error fetching user:', error);
    res.status(500).json({ error: 'Failed to fetch user data' });
  }
});

// Get all addresses for the current user
app.get('/api/addresses', validateSession, async (req, res) => {
  try {
    const userId = req.body.sessionUserId;
    const [addresses] = await db.query<AddressEntry[]>(
      'SELECT * FROM player_sg_fav_addresses WHERE user_id = ? ORDER BY order_int ASC',
      [userId]
    );

    // Convert database format to app format
    const formattedAddresses = addresses.map((addr: AddressEntry) => ({
      id: addr.id.toString(),
      value: addr.entry,
      labels: addr.labels ? addr.labels.split(',').map(l => l.trim()).filter(l => l) : [],
      updatedAt: Date.now() // Could add a timestamp column to track this
    }));

    res.json(formattedAddresses);
  } catch (error) {
    console.error('Error fetching addresses:', error);
    res.status(500).json({ error: 'Failed to fetch addresses' });
  }
});

// Add a new address
app.post('/api/addresses', validateSession, async (req, res) => {
  try {
    const userId = req.body.sessionUserId;
    const { entry, labels } = req.body;

    if (!entry) {
      return res.status(400).json({ error: 'Entry is required' });
    }

    // Get the max order_int to place new entry at the top
    const [maxOrder] = await db.query<any[]>(
      'SELECT COALESCE(MIN(order_int), 0) - 1 as next_order FROM player_sg_fav_addresses WHERE user_id = ?',
      [userId]
    );

    const orderInt = maxOrder[0].next_order;
    const labelsStr = Array.isArray(labels) ? labels.join(',') : '';

    const [result] = await db.query<any>(
      'INSERT INTO player_sg_fav_addresses (user_id, entry, labels, order_int) VALUES (?, ?, ?, ?)',
      [userId, entry, labelsStr, orderInt]
    );

    res.json({
      id: result.insertId.toString(),
      value: entry,
      labels: labels || [],
      updatedAt: Date.now()
    });
  } catch (error) {
    console.error('Error adding address:', error);
    res.status(500).json({ error: 'Failed to add address' });
  }
});

// Update an address
app.put('/api/addresses/:id', validateSession, async (req, res) => {
  try {
    const userId = req.body.sessionUserId;
    const { id } = req.params;
    const { entry, labels } = req.body;

    const updates: string[] = [];
    const values: any[] = [];

    if (entry !== undefined) {
      updates.push('entry = ?');
      values.push(entry);
    }

    if (labels !== undefined) {
      updates.push('labels = ?');
      values.push(Array.isArray(labels) ? labels.join(',') : labels);
    }

    if (updates.length === 0) {
      return res.status(400).json({ error: 'No updates provided' });
    }

    values.push(id, userId);

    await db.query(
      `UPDATE player_sg_fav_addresses SET ${updates.join(', ')} WHERE id = ? AND user_id = ?`,
      values
    );

    res.json({ success: true });
  } catch (error) {
    console.error('Error updating address:', error);
    res.status(500).json({ error: 'Failed to update address' });
  }
});

// Delete an address
app.delete('/api/addresses/:id', validateSession, async (req, res) => {
  try {
    const userId = req.body.sessionUserId;
    const { id } = req.params;

    await db.query(
      'DELETE FROM player_sg_fav_addresses WHERE id = ? AND user_id = ?',
      [id, userId]
    );

    res.json({ success: true });
  } catch (error) {
    console.error('Error deleting address:', error);
    res.status(500).json({ error: 'Failed to delete address' });
  }
});

// Reorder addresses
app.post('/api/addresses/reorder', validateSession, async (req, res) => {
  try {
    const userId = req.body.sessionUserId;
    const { orderedIds } = req.body; // Array of IDs in new order

    if (!Array.isArray(orderedIds)) {
      return res.status(400).json({ error: 'orderedIds must be an array' });
    }

    // Update order_int for each address
    const promises = orderedIds.map((id, index) =>
      db.query(
        'UPDATE player_sg_fav_addresses SET order_int = ? WHERE id = ? AND user_id = ?',
        [index, id, userId]
      )
    );

    await Promise.all(promises);
    res.json({ success: true });
  } catch (error) {
    console.error('Error reordering addresses:', error);
    res.status(500).json({ error: 'Failed to reorder addresses' });
  }
});

// Delete session (logout)
app.post('/api/logout', validateSession, async (req, res) => {
  try {
    const token = req.headers.authorization?.replace('Bearer ', '') || req.query.token as string;

    await db.query('DELETE FROM player_sessions WHERE token = ?', [token]);

    res.json({ success: true });
  } catch (error) {
    console.error('Error during logout:', error);
    res.status(500).json({ error: 'Logout failed' });
  }
});

app.listen(PORT, () => {
  console.log(`API server running on port ${PORT}`);
});
