import type { Request, Response } from "express";
import bcrypt from "bcryptjs";
import { prisma } from "../../config/prisma.js";
import { ApiError, asyncHandler } from "../../utils/asyncHandler.js";
import { audit } from "../../utils/audit.js";

export const listUsers = asyncHandler(async (_req: Request, res: Response) => {
  const users = await prisma.user.findMany({
    select: {
      id: true, fullName: true, email: true, phone: true, isActive: true, lastLogin: true, createdAt: true,
      roles: { select: { role: { select: { id: true, name: true, description: true } } } },
    },
    orderBy: { createdAt: "desc" },
  });
  res.json({ success: true, data: users.map((u) => ({ ...u, roles: u.roles.map((r) => r.role) })) });
});

export const getUser = asyncHandler(async (req: Request, res: Response) => {
  const user = await prisma.user.findUnique({
    where: { id: Number(req.params.id) },
    select: {
      id: true, fullName: true, email: true, phone: true, isActive: true, lastLogin: true, createdAt: true,
      roles: { select: { roleId: true } },
    },
  });
  if (!user) throw new ApiError(404, "المستخدم غير موجود");
  res.json({ success: true, data: { ...user, roleIds: user.roles.map((r) => r.roleId) } });
});

export const createUser = asyncHandler(async (req: Request, res: Response) => {
  const { fullName, email, password, phone, isActive, roleIds } = req.body;
  const exists = await prisma.user.findUnique({ where: { email: String(email).toLowerCase() } });
  if (exists) throw new ApiError(409, "البريد الإلكتروني مستخدم بالفعل");

  const user = await prisma.user.create({
    data: {
      fullName,
      email: String(email).toLowerCase(),
      passwordHash: await bcrypt.hash(password, 10),
      phone: phone ?? null,
      isActive: isActive ?? true,
      roles: roleIds?.length
        ? { create: roleIds.map((roleId: number) => ({ roleId })) }
        : undefined,
    },
  });
  await audit(req, "create", "user", user.id, null, { fullName, email });
  res.status(201).json({ success: true, data: user });
});

export const updateUser = asyncHandler(async (req: Request, res: Response) => {
  const id = Number(req.params.id);
  const { fullName, email, phone, isActive, password, roleIds } = req.body;
  const existing = await prisma.user.findUnique({ where: { id } });
  if (!existing) throw new ApiError(404, "المستخدم غير موجود");

  const user = await prisma.$transaction(async (tx) => {
    const updated = await tx.user.update({
      where: { id },
      data: {
        fullName: fullName ?? existing.fullName,
        email: email ? String(email).toLowerCase() : existing.email,
        phone: phone !== undefined ? phone : existing.phone,
        isActive: isActive ?? existing.isActive,
        passwordHash: password ? await bcrypt.hash(password, 10) : existing.passwordHash,
      },
    });
    if (roleIds) {
      await tx.userRole.deleteMany({ where: { userId: id } });
      if (roleIds.length) {
        await tx.userRole.createMany({ data: roleIds.map((roleId: number) => ({ userId: id, roleId })) });
      }
    }
    return updated;
  });

  await audit(req, "update", "user", id, { email: existing.email }, { fullName, email });
  res.json({ success: true, data: user });
});

export const deleteUser = asyncHandler(async (req: Request, res: Response) => {
  const id = Number(req.params.id);
  if (id === req.user!.id) throw new ApiError(400, "لا يمكنك حذف حسابك");
  const existing = await prisma.user.findUnique({ where: { id } });
  if (!existing) throw new ApiError(404, "المستخدم غير موجود");
  await prisma.user.delete({ where: { id } });
  await audit(req, "delete", "user", id, { email: existing.email }, null);
  res.json({ success: true });
});

// ============ Roles ============

export const listRoles = asyncHandler(async (_req: Request, res: Response) => {
  const roles = await prisma.role.findMany({
    include: { rolePerms: { include: { permission: true } } },
    orderBy: { id: "asc" },
  });
  res.json({
    success: true,
    data: roles.map((r) => ({ id: r.id, name: r.name, description: r.description, permissionIds: r.rolePerms.map((rp) => rp.permissionId) })),
  });
});

export const createRole = asyncHandler(async (req: Request, res: Response) => {
  const { name, description } = req.body;
  const exists = await prisma.role.findUnique({ where: { name } });
  if (exists) throw new ApiError(409, "اسم الدور مستخدم بالفعل");
  const role = await prisma.role.create({ data: { name, description } });
  await audit(req, "create", "role", role.id);
  res.status(201).json({ success: true, data: role });
});

export const updateRole = asyncHandler(async (req: Request, res: Response) => {
  const id = Number(req.params.id);
  const { name, description } = req.body;
  const existing = await prisma.role.findUnique({ where: { id } });
  if (!existing) throw new ApiError(404, "الدور غير موجود");
  const role = await prisma.role.update({ where: { id }, data: { name, description } });
  await audit(req, "update", "role", id);
  res.json({ success: true, data: role });
});

export const deleteRole = asyncHandler(async (req: Request, res: Response) => {
  const id = Number(req.params.id);
  const existing = await prisma.role.findUnique({ where: { id } });
  if (!existing) throw new ApiError(404, "الدور غير موجود");
  if (existing.name === "super_admin") throw new ApiError(400, "لا يمكن حذف دور المدير الأعلى");
  await prisma.role.delete({ where: { id } });
  await audit(req, "delete", "role", id);
  res.json({ success: true });
});

export const setRolePermissions = asyncHandler(async (req: Request, res: Response) => {
  const id = Number(req.params.id);
  const { permissionIds } = req.body;
  const role = await prisma.role.findUnique({ where: { id } });
  if (!role) throw new ApiError(404, "الدور غير موجود");
  await prisma.rolePermission.deleteMany({ where: { roleId: id } });
  if (permissionIds.length) {
    await prisma.rolePermission.createMany({ data: permissionIds.map((permissionId: number) => ({ roleId: id, permissionId })) });
  }
  await audit(req, "update_permissions", "role", id, null, { permissionIds });
  res.json({ success: true });
});

export const listPermissions = asyncHandler(async (_req: Request, res: Response) => {
  const permissions = await prisma.permission.findMany({ orderBy: { id: "asc" } });
  res.json({ success: true, data: permissions });
});
