import type { NextFunction, Request, Response } from "express";
import jwt from "jsonwebtoken";
import { env } from "../config/env.js";
import { prisma } from "../config/prisma.js";
import { ApiError } from "../utils/asyncHandler.js";

export interface AuthUser {
  id: number;
  fullName: string;
  email: string;
  roles: string[];
  permissions: string[];
}

declare global {
  namespace Express {
    interface Request {
      user?: AuthUser;
    }
  }
}

export function signTokens(user: { id: number }) {
  const accessToken = jwt.sign({ sub: user.id }, env.jwtAccessSecret, {
    expiresIn: env.jwtAccessExpires,
  } as jwt.SignOptions);
  const refreshToken = jwt.sign({ sub: user.id }, env.jwtRefreshSecret, {
    expiresIn: env.jwtRefreshExpires,
  } as jwt.SignOptions);
  return { accessToken, refreshToken };
}

export async function authenticate(req: Request, _res: Response, next: NextFunction) {
  try {
    const header = req.headers.authorization;
    if (!header || !header.startsWith("Bearer ")) {
      throw new ApiError(401, "غير مصرح. يرجى تسجيل الدخول");
    }
    const token = header.slice(7);
    const payload = jwt.verify(token, env.jwtAccessSecret) as jwt.JwtPayload;
    const userId = Number(payload.sub);
    if (!userId) throw new ApiError(401, "رمز غير صالح");

    const user = await prisma.user.findUnique({
      where: { id: userId },
      include: {
        roles: { include: { role: { include: { rolePerms: { include: { permission: true } } } } } },
      },
    });

    if (!user || !user.isActive) {
      throw new ApiError(401, "الحساب غير موجود أو معطل");
    }

    const roles = user.roles.map((r) => 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);
      }
    }

    req.user = {
      id: user.id,
      fullName: user.fullName,
      email: user.email,
      roles,
      permissions: Array.from(permissions),
    };
    next();
  } catch (err) {
    next(err);
  }
}

export function authorize(...required: string[]) {
  return (req: Request, _res: Response, next: NextFunction) => {
    if (!req.user) return next(new ApiError(401, "غير مصرح"));
    if (req.user.roles.includes("super_admin")) return next();
    const hasAll = required.every((p) => req.user!.permissions.includes(p));
    if (!hasAll) {
      return next(new ApiError(403, "لا تملك صلاحية تنفيذ هذا الإجراء"));
    }
    next();
  };
}
