import { Request, Response } from 'express';
import { Role } from '../models/Role';

// Get all roles
export const getRoles = async (req: Request, res: Response) => {
  try {
    const roles = await Role.find({ isActive: true }).sort({ name: 1 });
    res.json({ success: true, data: roles });
  } catch (error: any) {
    res.status(500).json({ success: false, message: error.message });
  }
};

// Get all roles including inactive
export const getAllRoles = async (req: Request, res: Response) => {
  try {
    const roles = await Role.find({}).sort({ name: 1 });
    res.json({ success: true, data: roles });
  } catch (error: any) {
    res.status(500).json({ success: false, message: error.message });
  }
};

// Get single role by ID
export const getRoleById = async (req: Request, res: Response) => {
  try {
    const { id } = req.params;
    const role = await Role.findById(id);
    
    if (!role) {
      return res.status(404).json({ success: false, message: 'Role not found' });
    }
    
    res.json({ success: true, data: role });
  } catch (error: any) {
    res.status(500).json({ success: false, message: error.message });
  }
};

// Create new role
export const createRole = async (req: Request, res: Response) => {
  try {
    const { name, code, description, permissions, isSystem } = req.body;

    // Validate required fields
    if (!name || !code) {
      return res.status(400).json({ success: false, message: 'Name and code are required' });
    }

    // Check if role with same name or code exists
    const existingRole = await Role.findOne({
      $or: [{ name }, { code: code.toUpperCase() }]
    });

    if (existingRole) {
      return res.status(400).json({ success: false, message: 'Role with this name or code already exists' });
    }

    const newRole = new Role({
      name,
      code: code.toUpperCase(),
      description,
      permissions: permissions || {},
      isSystem: isSystem || false,
      isActive: true,
    });

    await newRole.save();

    res.status(201).json({ success: true, message: 'Role created successfully', data: newRole });
  } catch (error: any) {
    res.status(500).json({ success: false, message: error.message });
  }
};

// Update role
export const updateRole = async (req: Request, res: Response) => {
  try {
    const { id } = req.params;
    const updateData = { ...req.body };

    // Remove _id from update data
    delete updateData._id;

    // If code is being updated, ensure it's uppercase
    if (updateData.code) {
      updateData.code = updateData.code.toUpperCase();
    }

    // Check for duplicate name or code if updating
    if (updateData.name || updateData.code) {
      const existingRole = await Role.findOne({
        _id: { $ne: id },
        $or: [
          updateData.name ? { name: updateData.name } : {},
          updateData.code ? { code: updateData.code.toUpperCase() } : {}
        ]
      });

      if (existingRole) {
        return res.status(400).json({ success: false, message: 'Role with this name or code already exists' });
      }
    }

    const role = await Role.findByIdAndUpdate(
      id,
      { $set: updateData },
      { new: true, runValidators: true }
    );

    if (!role) {
      return res.status(404).json({ success: false, message: 'Role not found' });
    }

    res.json({ success: true, message: 'Role updated successfully', data: role });
  } catch (error: any) {
    res.status(500).json({ success: false, message: error.message });
  }
};

// Update role permissions
export const updateRolePermissions = async (req: Request, res: Response) => {
  try {
    const { id } = req.params;
    const { permissions } = req.body;

    if (!permissions || typeof permissions !== 'object') {
      return res.status(400).json({ success: false, message: 'Permissions object is required' });
    }

    const role = await Role.findByIdAndUpdate(
      id,
      { $set: { permissions } },
      { new: true, runValidators: true }
    );

    if (!role) {
      return res.status(404).json({ success: false, message: 'Role not found' });
    }

    res.json({ success: true, message: 'Permissions updated successfully', data: role });
  } catch (error: any) {
    res.status(500).json({ success: false, message: error.message });
  }
};

// Delete role (soft delete by setting isActive to false, or hard delete if not system role)
export const deleteRole = async (req: Request, res: Response) => {
  try {
    const { id } = req.params;
    const { hardDelete } = req.query;

    const role = await Role.findById(id);

    if (!role) {
      return res.status(404).json({ success: false, message: 'Role not found' });
    }

    // Prevent deletion of system roles
    if (role.isSystem && hardDelete === 'true') {
      return res.status(400).json({ success: false, message: 'Cannot delete system roles' });
    }

    if (hardDelete === 'true' && !role.isSystem) {
      // Hard delete
      await Role.findByIdAndDelete(id);
      res.json({ success: true, message: 'Role deleted successfully' });
    } else {
      // Soft delete
      role.isActive = false;
      await role.save();
      res.json({ success: true, message: 'Role deactivated successfully', data: role });
    }
  } catch (error: any) {
    res.status(500).json({ success: false, message: error.message });
  }
};

// Get all available permission keys (for UI)
export const getPermissionKeys = async (req: Request, res: Response) => {
  try {
    // Get all unique permission keys from all roles
    const roles = await Role.find({});
    const permissionKeys = new Set<string>();

    roles.forEach(role => {
      Object.keys(role.permissions || {}).forEach(key => {
        permissionKeys.add(key);
      });
    });

    res.json({ success: true, data: Array.from(permissionKeys).sort() });
  } catch (error: any) {
    res.status(500).json({ success: false, message: error.message });
  }
};
