import type { Request, Response } from "express";
import bcrypt from "bcryptjs";
import jwt from "jsonwebtoken";
import { prisma } from "../../config/prisma.js";
import { env } from "../../config/env.js";
import { ApiError, asyncHandler } from "../../utils/asyncHandler.js";
import { signTokens } from "../../middleware/auth.js";
import { audit } from "../../utils/audit.js";

function buildUserPayload(user: any) {
  const roles = user.roles.map((r: any) => r.role.name);
  const permissions = new Set<string>();
  for (const r of user.roles) {
    for (const rp of r.role.rolePerms) permissions.add(rp.permission.code);
  }
  return {
    id: user.id,
    fullName: user.fullName,
    email: user.email,
    phone: user.phone,
    roles,
    permissions: Array.from(permissions),
  };
}

export const login = asyncHandler(async (req: Request, res: Response) => {
  const { email, password } = req.body;
  const user = await prisma.user.findUnique({
    where: { email: String(email).toLowerCase() },
    include: { roles: { include: { role: { include: { rolePerms: { include: { permission: true } } } } } } },
  });

  if (!user || !(await bcrypt.compare(password, user.passwordHash))) {
    throw new ApiError(401, "بيانات الدخول غير صحيحة");
  }
  if (!user.isActive) {
    throw new ApiError(403, "الحساب معطل، تواصل مع المدير");
  }

  await prisma.user.update({ where: { id: user.id }, data: { lastLogin: new Date() } });
  const { accessToken, refreshToken } = signTokens(user);
  await audit(req, "login", "user", user.id);
  res.json({ success: true, user: buildUserPayload(user), accessToken, refreshToken });
});

export const refresh = asyncHandler(async (req: Request, res: Response) => {
  const { refreshToken } = req.body;
  let payload: any;
  try {
    payload = jwt.verify(refreshToken, env.jwtRefreshSecret);
  } catch {
    throw new ApiError(401, "رمز التحديث غير صالح أو منتهي");
  }
  const user = await prisma.user.findUnique({
    where: { id: payload.sub },
    include: { roles: { include: { role: { include: { rolePerms: { include: { permission: true } } } } } } },
  });
  if (!user || !user.isActive) throw new ApiError(401, "الحساب غير موجود أو معطل");
  const tokens = signTokens(user);
  res.json({ success: true, user: buildUserPayload(user), ...tokens });
});

export const me = asyncHandler(async (req: Request, res: Response) => {
  const user = await prisma.user.findUnique({
    where: { id: req.user!.id },
    include: { roles: { include: { role: { include: { rolePerms: { include: { permission: true } } } } } } },
  });
  if (!user) throw new ApiError(404, "المستخدم غير موجود");
  res.json({ success: true, user: buildUserPayload(user) });
});

export const logout = asyncHandler(async (req: Request, res: Response) => {
  await audit(req, "logout", "user", req.user!.id);
  res.json({ success: true });
});

export const changePassword = asyncHandler(async (req: Request, res: Response) => {
  const { currentPassword, newPassword } = req.body;
  const user = await prisma.user.findUnique({ where: { id: req.user!.id } });
  if (!user) throw new ApiError(404, "المستخدم غير موجود");
  if (!(await bcrypt.compare(currentPassword, user.passwordHash))) {
    throw new ApiError(400, "كلمة المرور الحالية غير صحيحة");
  }
  await prisma.user.update({
    where: { id: user.id },
    data: { passwordHash: await bcrypt.hash(newPassword, 10) },
  });
  await audit(req, "change_password", "user", user.id);
  res.json({ success: true, message: "تم تغيير كلمة المرور بنجاح" });
});
