import type { Request, Response, NextFunction } from 'express';
import type { Prisma } from '@prisma/client';
import * as roleModel from '../models/role.model.js';
import { successResponse, errorResponse } from '../utils/response.js';
import { parsePagination, paginatedResponse } from '../utils/pagination.js';

type RoleWithPermissions = Prisma.RoleGetPayload<{ include: { permissions: { include: { permission: true } } } }>;

function withFlatPermissions(role: RoleWithPermissions) {
  return { ...role, permissions: role.permissions.map((rolePermission) => rolePermission.permission) };
}

async function createRole(req: Request, res: Response, next: NextFunction) {
  try {
    const role = await roleModel.createRole(req.body);
    return successResponse(res, 'Role created successfully', role, 201);
  } catch (error) {
    next(error);
    return;
  }
}

async function getRoles(req: Request, res: Response, next: NextFunction) {
  try {
    const pagination = parsePagination(req.query);
    const [roles, total] = await Promise.all([
      roleModel.getRoles(pagination),
      roleModel.countRoles(),
    ]);
    return successResponse(res, 'Roles fetched successfully', paginatedResponse(roles.map(withFlatPermissions), total, pagination));
  } catch (error) {
    next(error);
    return;
  }
}

async function getRole(req: Request, res: Response, next: NextFunction) {
  try {
    const role = await roleModel.getRoleById(Number(req.params.id));
    if (!role) return void errorResponse(res, 'Role not found', 404);
    return successResponse(res, 'Role fetched successfully', withFlatPermissions(role));
  } catch (error) {
    next(error);
    return;
  }
}

async function updateRole(req: Request, res: Response, next: NextFunction) {
  try {
    const role = await roleModel.updateRole(Number(req.params.id), req.body);
    return successResponse(res, 'Role updated successfully', role);
  } catch (error) {
    next(error);
    return;
  }
}

async function deleteRole(req: Request, res: Response, next: NextFunction) {
  try {
    await roleModel.deleteRole(Number(req.params.id));
    return successResponse(res, 'Role deleted successfully');
  } catch (error) {
    next(error);
    return;
  }
}

async function setRolePermissions(req: Request, res: Response, next: NextFunction) {
  try {
    const role = await roleModel.setRolePermissions(Number(req.params.id), req.body.permissionIds);
    if (!role) return void errorResponse(res, 'Role not found', 404);
    return successResponse(res, 'Role permissions updated', withFlatPermissions(role));
  } catch (error) {
    next(error);
    return;
  }
}

export { createRole, getRoles, getRole, updateRole, deleteRole, setRolePermissions };
