const express = require('express');
const router = express.Router();
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const { requirePermission, getUserPermissions } = require('./permissions');

// Get pool from global or create a new one if not available
let pool;
if (typeof global.pool !== 'undefined') {
  pool = global.pool;
} else {
  // If global pool is not available, create a new connection
  const { Pool } = require('pg');
  pool = new Pool({
    host: process.env.DB_HOST,
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    database: process.env.DB_NAME,
    port: process.env.DB_PORT,
  });
  console.log('Created new database pool in routes.js');
}

// Authentication middleware
const authenticate = async (req, res, next) => {
  try {
    const authHeader = req.headers.authorization;
    if (!authHeader || !authHeader.startsWith('Bearer ')) {
      return res.status(401).json({ error: 'Authentication required' });
    }

    const token = authHeader.split(' ')[1];
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    
    // Get user from database
    const result = await pool.query(
      'SELECT id, username, email, is_admin, rocket_chat_user_id FROM users WHERE id = $1',
      [decoded.userId]
    );
    
    console.log('Database query result for user', decoded.userId, ':', result.rows[0]);
    
    if (result.rows.length === 0) {
      return res.status(401).json({ error: 'User not found' });
    }
    
    // Attach user to request
    req.user = result.rows[0];
    next();
  } catch (error) {
    console.error('Authentication error:', error);
    res.status(401).json({ error: 'Invalid token' });
  }
};

// Login route
router.post('/login', async (req, res) => {
  try {
    const { username, password } = req.body;
    
    // Get user from database
    const result = await pool.query(
      'SELECT id, username, password, is_admin, is_active, rocket_chat_user_id FROM users WHERE username = $1',
      [username]
    );
    
    if (result.rows.length === 0) {
      return res.status(401).json({ error: 'Invalid username or password' });
    }
    
    const user = result.rows[0];
    
    // Check if user is active
    if (!user.is_active) {
      return res.status(403).json({ error: 'Account is inactive' });
    }
    
    // Verify password
    const validPassword = await bcrypt.compare(password, user.password);
    if (!validPassword) {
      return res.status(401).json({ error: 'Invalid username or password' });
    }
    
    // Update last login
    await pool.query(
      'UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE id = $1',
      [user.id]
    );
    
    // Generate JWT
    const token = jwt.sign(
      { userId: user.id, username: user.username },
      process.env.JWT_SECRET,
      { expiresIn: '8h' }
    );
    
    // Get user permissions
    const permissions = await getUserPermissions(user.id);
    
    res.json({
      token,
      user: {
        id: user.id,
        username: user.username,
        is_admin: user.is_admin,
        rocket_chat_user_id: user.rocket_chat_user_id,
        permissions
      }
    });
  } catch (error) {
    console.error('Login error:', error);
    res.status(500).json({ error: 'Server error' });
  }
});

// Get current user
router.get('/me', authenticate, async (req, res) => {
  try {
    // Get user permissions
    const permissions = await getUserPermissions(req.user.id);
    
    res.json({
      id: req.user.id,
      username: req.user.username,
      email: req.user.email,
      is_admin: req.user.is_admin,
      rocket_chat_user_id: req.user.rocket_chat_user_id,
      permissions,
      // Debug info
      _debug_raw_user: req.user,
      _server_identifier: "INVENTORY_AUTH_SERVER_MODIFIED"
    });
  } catch (error) {
    console.error('Error getting current user:', error);
    res.status(500).json({ error: 'Server error' });
  }
});

// Get all users
router.get('/users', authenticate, requirePermission('view:users'), async (req, res) => {
  try {
    const result = await pool.query(`
      SELECT id, username, email, is_admin, is_active, rocket_chat_user_id, created_at, last_login
      FROM users
      ORDER BY username
    `);
    
    res.json(result.rows);
  } catch (error) {
    console.error('Error getting users:', error);
    res.status(500).json({ error: 'Server error' });
  }
});

// Get user with permissions
router.get('/users/:id', authenticate, requirePermission('view:users'), async (req, res) => {
  try {
    const userId = req.params.id;
    
    // Get user details
    const userResult = await pool.query(`
      SELECT id, username, email, is_admin, is_active, rocket_chat_user_id, created_at, last_login
      FROM users
      WHERE id = $1
    `, [userId]);
    
    if (userResult.rows.length === 0) {
      return res.status(404).json({ error: 'User not found' });
    }
    
    // Get user permissions
    const permissionsResult = await pool.query(`
      SELECT p.id, p.name, p.code, p.category, p.description
      FROM permissions p
      JOIN user_permissions up ON p.id = up.permission_id
      WHERE up.user_id = $1
      ORDER BY p.category, p.name
    `, [userId]);
    
    // Combine user and permissions
    const user = {
      ...userResult.rows[0],
      permissions: permissionsResult.rows
    };
    
    res.json(user);
  } catch (error) {
    console.error('Error getting user:', error);
    res.status(500).json({ error: 'Server error' });
  }
});

// Create new user
router.post('/users', authenticate, requirePermission('create:users'), async (req, res) => {
  const client = await pool.connect();
  
  try {
    const { username, email, password, is_admin, is_active, rocket_chat_user_id, permissions } = req.body;
    
    console.log("Create user request:", {
      username,
      email,
      is_admin,
      is_active,
      rocket_chat_user_id,
      permissions: permissions || []
    });
    
    // Validate required fields
    if (!username || !password) {
      return res.status(400).json({ error: 'Username and password are required' });
    }
    
    // Check if username is taken
    const existingUser = await client.query(
      'SELECT id FROM users WHERE username = $1',
      [username]
    );
    
    if (existingUser.rows.length > 0) {
      return res.status(400).json({ error: 'Username already exists' });
    }
    
    // Start transaction
    await client.query('BEGIN');
    
    // Hash password
    const saltRounds = 10;
    const hashedPassword = await bcrypt.hash(password, saltRounds);
    
    // Insert new user
    const userResult = await client.query(`
      INSERT INTO users (username, email, password, is_admin, is_active, rocket_chat_user_id, created_at)
      VALUES ($1, $2, $3, $4, $5, $6, CURRENT_TIMESTAMP)
      RETURNING id
    `, [username, email || null, hashedPassword, !!is_admin, is_active !== false, rocket_chat_user_id || null]);
    
    const userId = userResult.rows[0].id;
    
    // Assign permissions if provided and not admin
    if (!is_admin && Array.isArray(permissions) && permissions.length > 0) {
      console.log("Adding permissions for new user:", userId);
      console.log("Permissions received:", permissions);
      
      // Check permission format
      const permissionIds = permissions.map(p => {
        if (typeof p === 'object' && p.id) {
          console.log("Permission is an object with ID:", p.id);
          return parseInt(p.id, 10);
        } else if (typeof p === 'number') {
          console.log("Permission is a number:", p);
          return p;
        } else if (typeof p === 'string' && !isNaN(parseInt(p, 10))) {
          console.log("Permission is a string that can be parsed as a number:", p);
          return parseInt(p, 10);
        } else {
          console.log("Unknown permission format:", typeof p, p);
          // If it's a permission code, we need to look up the ID
          return null;
        }
      }).filter(id => id !== null);
      
      console.log("Filtered permission IDs:", permissionIds);
      
      if (permissionIds.length > 0) {
        const permissionValues = permissionIds
          .map(permId => `(${userId}, ${permId})`)
          .join(',');
        
        console.log("Inserting permission values:", permissionValues);
        
        try {
          await client.query(`
            INSERT INTO user_permissions (user_id, permission_id)
            VALUES ${permissionValues}
            ON CONFLICT DO NOTHING
          `);
          console.log("Successfully inserted permissions for new user:", userId);
        } catch (err) {
          console.error("Error inserting permissions for new user:", err);
          throw err;
        }
      } else {
        console.log("No valid permission IDs found to insert for new user");
      }
    } else {
      console.log("Not adding permissions: is_admin =", is_admin, "permissions array:", Array.isArray(permissions), "length:", permissions ? permissions.length : 0);
    }
    
    await client.query('COMMIT');
    
    res.status(201).json({ 
      id: userId, 
      message: 'User created successfully' 
    });
  } catch (error) {
    await client.query('ROLLBACK');
    console.error('Error creating user:', error);
    res.status(500).json({ error: 'Server error' });
  } finally {
    client.release();
  }
});

// Update user
router.put('/users/:id', authenticate, requirePermission('edit:users'), async (req, res) => {
  const client = await pool.connect();
  
  try {
    const userId = req.params.id;
    const { username, email, password, is_admin, is_active, rocket_chat_user_id, permissions } = req.body;
    
    console.log("Update user request:", {
      userId,
      username,
      email,
      is_admin,
      is_active,
      rocket_chat_user_id,
      permissions: permissions || []
    });
    
    // Check if user exists
    const userExists = await client.query(
      'SELECT id FROM users WHERE id = $1',
      [userId]
    );
    
    if (userExists.rows.length === 0) {
      return res.status(404).json({ error: 'User not found' });
    }
    
    // Start transaction
    await client.query('BEGIN');
    
    // Build update fields
    const updateFields = [];
    const updateValues = [userId]; // First parameter is the user ID
    let paramIndex = 2;
    
    if (username !== undefined) {
      updateFields.push(`username = $${paramIndex++}`);
      updateValues.push(username);
    }
    
    if (email !== undefined) {
      updateFields.push(`email = $${paramIndex++}`);
      updateValues.push(email || null);
    }
    
    if (is_admin !== undefined) {
      updateFields.push(`is_admin = $${paramIndex++}`);
      updateValues.push(!!is_admin);
    }
    
    if (is_active !== undefined) {
      updateFields.push(`is_active = $${paramIndex++}`);
      updateValues.push(!!is_active);
    }
    
    if (rocket_chat_user_id !== undefined) {
      updateFields.push(`rocket_chat_user_id = $${paramIndex++}`);
      updateValues.push(rocket_chat_user_id || null);
    }
    
    // Update password if provided
    if (password) {
      const saltRounds = 10;
      const hashedPassword = await bcrypt.hash(password, saltRounds);
      updateFields.push(`password = $${paramIndex++}`);
      updateValues.push(hashedPassword);
    }
    
    // Update user if there are fields to update
    if (updateFields.length > 0) {
      updateFields.push(`updated_at = CURRENT_TIMESTAMP`);
      
      await client.query(`
        UPDATE users
        SET ${updateFields.join(', ')}
        WHERE id = $1
      `, updateValues);
    }
    
    // Update permissions if provided
    if (Array.isArray(permissions)) {
      console.log("Updating permissions for user:", userId);
      console.log("Permissions received:", permissions);
      
      // First remove existing permissions
      await client.query(
        'DELETE FROM user_permissions WHERE user_id = $1',
        [userId]
      );
      console.log("Deleted existing permissions for user:", userId);
      
      // Add new permissions if any and not admin
      const newIsAdmin = is_admin !== undefined ? is_admin : (await client.query('SELECT is_admin FROM users WHERE id = $1', [userId])).rows[0].is_admin;
      
      console.log("User is admin:", newIsAdmin);
      
      if (!newIsAdmin && permissions.length > 0) {
        console.log("Adding permissions:", permissions);
        
        // Check permission format
        const permissionIds = permissions.map(p => {
          if (typeof p === 'object' && p.id) {
            console.log("Permission is an object with ID:", p.id);
            return parseInt(p.id, 10);
          } else if (typeof p === 'number') {
            console.log("Permission is a number:", p);
            return p;
          } else if (typeof p === 'string' && !isNaN(parseInt(p, 10))) {
            console.log("Permission is a string that can be parsed as a number:", p);
            return parseInt(p, 10);
          } else {
            console.log("Unknown permission format:", typeof p, p);
            // If it's a permission code, we need to look up the ID
            return null;
          }
        }).filter(id => id !== null);
        
        console.log("Filtered permission IDs:", permissionIds);
        
        if (permissionIds.length > 0) {
          const permissionValues = permissionIds
            .map(permId => `(${userId}, ${permId})`)
            .join(',');
          
          console.log("Inserting permission values:", permissionValues);
          
          try {
            await client.query(`
              INSERT INTO user_permissions (user_id, permission_id)
              VALUES ${permissionValues}
              ON CONFLICT DO NOTHING
            `);
            console.log("Successfully inserted permissions for user:", userId);
          } catch (err) {
            console.error("Error inserting permissions:", err);
            throw err;
          }
        } else {
          console.log("No valid permission IDs found to insert");
        }
      }
    }
    
    await client.query('COMMIT');
    
    res.json({ message: 'User updated successfully' });
  } catch (error) {
    await client.query('ROLLBACK');
    console.error('Error updating user:', error);
    res.status(500).json({ error: 'Server error' });
  } finally {
    client.release();
  }
});

// Delete user
router.delete('/users/:id', authenticate, requirePermission('delete:users'), async (req, res) => {
  try {
    const userId = req.params.id;
    
    // Check that user is not deleting themselves
    if (req.user.id === parseInt(userId, 10)) {
      return res.status(400).json({ error: 'Cannot delete your own account' });
    }
    
    // Delete user (this will cascade to user_permissions due to FK constraints)
    const result = await pool.query(
      'DELETE FROM users WHERE id = $1 RETURNING id',
      [userId]
    );
    
    if (result.rows.length === 0) {
      return res.status(404).json({ error: 'User not found' });
    }
    
    res.json({ message: 'User deleted successfully' });
  } catch (error) {
    console.error('Error deleting user:', error);
    res.status(500).json({ error: 'Server error' });
  }
});

// Get all permissions grouped by category
router.get('/permissions/categories', authenticate, requirePermission('view:users'), async (req, res) => {
  try {
    const result = await pool.query(`
      SELECT category, json_agg(
        json_build_object(
          'id', id,
          'name', name,
          'code', code,
          'description', description
        ) ORDER BY name
      ) as permissions
      FROM permissions
      GROUP BY category
      ORDER BY category
    `);
    
    res.json(result.rows);
  } catch (error) {
    console.error('Error getting permissions:', error);
    res.status(500).json({ error: 'Server error' });
  }
});

// Get all permissions
router.get('/permissions', authenticate, requirePermission('view:users'), async (req, res) => {
  try {
    const result = await pool.query(`
      SELECT *
      FROM permissions
      ORDER BY category, name
    `);
    
    res.json(result.rows);
  } catch (error) {
    console.error('Error getting permissions:', error);
    res.status(500).json({ error: 'Server error' });
  }
});

module.exports = router; 