import { Request, Response } from 'express';
import { Permission, Role, User } from '../models';
import {
  createRoleSchema,
  assignRoleSchema,
  editRoleSchema,
  getRoleSchema,
} from '../validators/authValidator';
import { verifyAccess } from '../middlewares/authentication';

export const getPermissions = async (req: Request, res: Response) => {
  try {
    const validAccess = await verifyAccess(req, 'create_roles');
    if (!validAccess) {
      return res.status(403).json({
        success: false,
        message: 'Access denied',
      });
    }
    
    const permissions = await Permission.find({});
    return res.status(200).json({
      success: true,
      message: 'List of all available Permissions',
      data: permissions,
    });
  } catch (err: any) {
    return res.status(500).json({
      success: false,
      message: err.message,
    });
  }
};

export const createRole = async (req: Request, res: Response) => {
  const { company_id } = req.user!;
  const { error, value } = createRoleSchema.body.validate(req.body);

  if (error) {
    return res.status(400).json({
      success: false,
      message: error.details[0].message,
    });
  }
  const { role, permissions } = value;

  const validAccess = await verifyAccess(req, 'create_roles');
  if (!validAccess) {
    return res.status(403).json({
      success: false,
      message: 'Access denied',
    });
  }

  try {
    const existing = await Role.findOne({ company_id, role });
    if (existing)
      return res.status(401).json({
        success: false,
        message: 'Role already exists',
      });

    const newRole = await Role.create({
      company_id,
      role,
      permissions,
    });

    return res.status(201).json({
      success: true,
      message: 'Role created successfully',
      data: {
        role: newRole,
      },
    });
  } catch (err: any) {
    return res.status(500).json({
      success: false,
      message: err.message,
    });
  }
};

export const assignRole = async (req: Request, res: Response) => {
  const { company_id } = req.user!;
  const { error, value } = assignRoleSchema.body.validate(req.body);

  if (error) {
    return res.status(400).json({
      success: false,
      message: error.details[0].message,
    });
  }
  const { roleID, userID } = value;

  const validAccess = await verifyAccess(req, 'create_users');
  if (!validAccess) {
    return res.status(403).json({
      success: false,
      message: 'Access denied',
    });
  }

  try {
    const existing = await Role.findOne({ company_id, _id: roleID });
    if (!existing)
      return res.status(401).json({
        success: false,
        message: 'Role does not exist',
      });

    await User.updateMany(
      { _id: { $in: userID }, userType: 'staff', company_id },
      { role_id: roleID },
    );

    return res.status(201).json({
      success: true,
      message: 'Role assigned successfully',
    });
  } catch (err: any) {
    return res.status(500).json({
      success: false,
      message: err.message,
    });
  }
};

export const getRoles = async (req: Request, res: Response) => {
  const { company_id } = req.user!;
  const { error, value } = getRoleSchema.query.validate(req.query);

  if (error) {
    return res.status(400).json({
      success: false,
      message: error.details[0].message,
    });
  }
  const { roleID } = value;

  const validAccess = await verifyAccess(req, 'view_roles', 'create_users');
  if (!validAccess) {
    return res.status(403).json({
      success: false,
      message: 'Access denied',
    });
  }

  const selector = { company_id };
  try {
    if (roleID) {
      Object.assign(selector, { _id: roleID });
    }
    const roles = await Role.find(selector).populate('roleUsers', {
      firstName: 1,
      lastName: 1,
    });

    if (roleID && !roles.length)
      return res.status(404).json({
        success: false,
        message: 'Role does not exist',
      });

    return res.status(200).json({
      success: true,
      message: 'Roles request successful',
      data: {
        role: roleID ? roles[0] : roles,
      },
    });
  } catch (err: any) {
    return res.status(500).json({
      success: false,
      message: err.message,
    });
  }
};

export const editRole = async (req: Request, res: Response) => {
  const { company_id } = req.user!;
  const { error: errorParams, value: valueParams } =
    editRoleSchema.params.validate(req.params);
  const { error: errorBody, value: valueBody } = editRoleSchema.body.validate(
    req.body,
  );

  if (errorParams || errorBody) {
    return res.status(400).json({
      success: false,
      message: errorParams
        ? errorParams.details[0].message
        : errorBody!.details[0].message,
    });
  }
  const { roleID } = valueParams;
  const { role, permissions } = valueBody;

  const validAccess = await verifyAccess(req, 'create_roles');
  if (!validAccess) {
    return res.status(403).json({
      success: false,
      message: 'Access denied',
    });
  }

  const userRole = await Role.findOne({
    company_id,
    _id: roleID,
  });
  if (!userRole)
    return res.status(404).json({
      success: false,
      message: 'Role does not exist',
    });

  userRole.set({
    role,
    permissions,
  });
  await userRole.save();

  return res.status(201).json({
    success: true,
    message: 'Role updated successfully',
    data: {
      role: userRole,
    },
  });
};
