// User Management Routes (Admin only)
const express = require('express');
const bcrypt = require('bcryptjs');
const pool = require('../db');
const { validateTeams } = require('../helpers/teams');

function createUsersRouter(requireAuth, requireGroup, logAudit) {
    const router = express.Router();

    // All routes require Admin group
    router.use(requireAuth(), requireGroup('Admin'));

    // Get all users
    router.get('/', async (req, res) => {
        try {
            const { rows: users } = await pool.query(
                `SELECT id, username, email, user_group AS "group", bu_teams, is_active, created_at, last_login
                 FROM users ORDER BY created_at DESC`
            );
            // Parse bu_teams into teams array for each user
            const usersWithTeams = users.map(u => ({
                ...u,
                teams: u.bu_teams ? u.bu_teams.split(',').filter(Boolean) : []
            }));
            res.json(usersWithTeams);
        } catch (err) {
            console.error('Get users error:', err);
            res.status(500).json({ error: 'Failed to fetch users' });
        }
    });

    // Get single user
    router.get('/:id', async (req, res) => {
        try {
            const { rows } = await pool.query(
                `SELECT id, username, email, user_group AS "group", bu_teams, is_active, created_at, last_login
                 FROM users WHERE id = $1`,
                [req.params.id]
            );

            const user = rows[0];

            if (!user) {
                return res.status(404).json({ error: 'User not found' });
            }

            res.json({
                ...user,
                teams: user.bu_teams ? user.bu_teams.split(',').filter(Boolean) : []
            });
        } catch (err) {
            console.error('Get user error:', err);
            res.status(500).json({ error: 'Failed to fetch user' });
        }
    });

    // Create new user
    router.post('/', async (req, res) => {
        const { username, email, password, group, bu_teams } = req.body;
        const VALID_GROUPS = ['Admin', 'Standard_User', 'Leadership', 'Read_Only'];

        if (!username || !email || !password) {
            return res.status(400).json({ error: 'Username, email, and password are required' });
        }

        const userGroup = group || 'Read_Only';

        if (!VALID_GROUPS.includes(userGroup)) {
            return res.status(400).json({ error: 'Invalid group. Must be one of: Admin, Standard_User, Leadership, Read_Only' });
        }

        // Validate bu_teams if provided
        const teamsStr = bu_teams || '';
        if (teamsStr) {
            const teamsResult = validateTeams(teamsStr);
            if (!teamsResult.valid) {
                return res.status(400).json({ error: `Invalid team(s): ${teamsResult.invalid.join(', ')}. Must be one of: STEAM, ACCESS-ENG, ACCESS-OPS, INTELDEV` });
            }
        }

        try {
            const passwordHash = await bcrypt.hash(password, 10);

            const { rows } = await pool.query(
                `INSERT INTO users (username, email, password_hash, user_group, bu_teams)
                 VALUES ($1, $2, $3, $4, $5)
                 RETURNING id`,
                [username, email, passwordHash, userGroup, teamsStr]
            );

            const result = rows[0];

            logAudit({
                userId: req.user.id,
                username: req.user.username,
                action: 'user_create',
                entityType: 'user',
                entityId: String(result.id),
                details: { created_username: username, group: userGroup, bu_teams: teamsStr },
                ipAddress: req.ip
            });

            res.status(201).json({
                message: 'User created successfully',
                user: {
                    id: result.id,
                    username,
                    email,
                    group: userGroup,
                    bu_teams: teamsStr,
                    teams: teamsStr ? teamsStr.split(',').filter(Boolean) : []
                }
            });
        } catch (err) {
            console.error('Create user error:', err);
            if (err.code === '23505') { // Postgres unique violation
                return res.status(409).json({ error: 'Username or email already exists' });
            }
            res.status(500).json({ error: 'Failed to create user' });
        }
    });

    // Update user
    router.patch('/:id', async (req, res) => {
        const { username, email, password, group, is_active, bu_teams } = req.body;
        const VALID_GROUPS = ['Admin', 'Standard_User', 'Leadership', 'Read_Only'];
        const userId = req.params.id;

        // Validate group if provided
        if (group && !VALID_GROUPS.includes(group)) {
            return res.status(400).json({ error: 'Invalid group. Must be one of: Admin, Standard_User, Leadership, Read_Only' });
        }

        // Prevent admin self-demotion
        if (String(userId) === String(req.user.id) && group && group !== 'Admin') {
            return res.status(400).json({ error: 'Cannot remove your own admin group' });
        }

        // Prevent self-deactivation
        if (String(userId) === String(req.user.id) && is_active === false) {
            return res.status(400).json({ error: 'Cannot deactivate your own account' });
        }

        // Validate bu_teams if provided
        if (typeof bu_teams === 'string') {
            if (bu_teams !== '') {
                const teamsResult = validateTeams(bu_teams);
                if (!teamsResult.valid) {
                    return res.status(400).json({ error: `Invalid team(s): ${teamsResult.invalid.join(', ')}. Must be one of: STEAM, ACCESS-ENG, ACCESS-OPS, INTELDEV` });
                }
            }
        }

        try {
            // Fetch current user record before update (needed for group change audit)
            const { rows: currentRows } = await pool.query(
                'SELECT user_group, bu_teams FROM users WHERE id = $1',
                [userId]
            );

            const currentUser = currentRows[0];

            if (!currentUser) {
                return res.status(404).json({ error: 'User not found' });
            }

            const updates = [];
            const values = [];
            let paramIndex = 1;

            if (username) {
                updates.push(`username = $${paramIndex++}`);
                values.push(username);
            }
            if (email) {
                updates.push(`email = $${paramIndex++}`);
                values.push(email);
            }
            if (password) {
                const passwordHash = await bcrypt.hash(password, 10);
                updates.push(`password_hash = $${paramIndex++}`);
                values.push(passwordHash);
            }
            if (group) {
                updates.push(`user_group = $${paramIndex++}`);
                values.push(group);
            }
            if (typeof is_active === 'boolean') {
                updates.push(`is_active = $${paramIndex++}`);
                values.push(is_active);
            }
            if (typeof bu_teams === 'string') {
                updates.push(`bu_teams = $${paramIndex++}`);
                values.push(bu_teams);
            }

            if (updates.length === 0) {
                return res.status(400).json({ error: 'No fields to update' });
            }

            values.push(userId);

            await pool.query(
                `UPDATE users SET ${updates.join(', ')} WHERE id = $${paramIndex}`,
                values
            );

            const updatedFields = {};
            if (username) updatedFields.username = username;
            if (email) updatedFields.email = email;
            if (group) updatedFields.group = group;
            if (typeof is_active === 'boolean') updatedFields.is_active = is_active;
            if (password) updatedFields.password_changed = true;
            if (typeof bu_teams === 'string') updatedFields.bu_teams = bu_teams;

            logAudit({
                userId: req.user.id,
                username: req.user.username,
                action: 'user_update',
                entityType: 'user',
                entityId: String(userId),
                details: updatedFields,
                ipAddress: req.ip
            });

            // Log specific audit entry for group changes
            if (group && group !== currentUser.user_group) {
                logAudit({
                    userId: req.user.id,
                    username: req.user.username,
                    action: 'user_group_change',
                    entityType: 'user',
                    entityId: String(userId),
                    details: {
                        previous_group: currentUser.user_group,
                        new_group: group
                    },
                    ipAddress: req.ip
                });
            }

            // Log specific audit entry for bu_teams changes
            if (typeof bu_teams === 'string' && bu_teams !== (currentUser.bu_teams || '')) {
                logAudit({
                    userId: req.user.id,
                    username: req.user.username,
                    action: 'user_teams_change',
                    entityType: 'user',
                    entityId: String(userId),
                    details: {
                        previous_teams: currentUser.bu_teams || '',
                        new_teams: bu_teams
                    },
                    ipAddress: req.ip
                });
            }

            // If user was deactivated, delete their sessions
            if (is_active === false) {
                await pool.query('DELETE FROM sessions WHERE user_id = $1', [userId]);
            }

            res.json({ message: 'User updated successfully' });
        } catch (err) {
            console.error('Update user error:', err);
            if (err.code === '23505') { // Postgres unique violation
                return res.status(409).json({ error: 'Username or email already exists' });
            }
            res.status(500).json({ error: 'Failed to update user' });
        }
    });

    // Delete user
    router.delete('/:id', async (req, res) => {
        const userId = req.params.id;

        // Prevent self-deletion
        if (String(userId) === String(req.user.id)) {
            return res.status(400).json({ error: 'Cannot delete your own account' });
        }

        try {
            // Look up the user before deleting
            const { rows: userRows } = await pool.query(
                'SELECT username FROM users WHERE id = $1',
                [userId]
            );
            const targetUser = userRows[0];

            // Delete sessions first (foreign key)
            await pool.query('DELETE FROM sessions WHERE user_id = $1', [userId]);

            // Delete user
            const result = await pool.query('DELETE FROM users WHERE id = $1', [userId]);

            if (result.rowCount === 0) {
                return res.status(404).json({ error: 'User not found' });
            }

            logAudit({
                userId: req.user.id,
                username: req.user.username,
                action: 'user_delete',
                entityType: 'user',
                entityId: String(userId),
                details: { deleted_username: targetUser ? targetUser.username : 'unknown' },
                ipAddress: req.ip
            });

            res.json({ message: 'User deleted successfully' });
        } catch (err) {
            console.error('Delete user error:', err);
            res.status(500).json({ error: 'Failed to delete user' });
        }
    });

    return router;
}

module.exports = createUsersRouter;
