import { prisma } from '../../config/database';
import { generateOtp, storeOtp, verifyOtp, sendOtpSms, checkOtpRateLimit } from '../../utils/otp';
import { generateAccessToken, generateRefreshToken, verifyRefreshToken, revokeRefreshToken } from '../../utils/jwt';

export async function sendOtpToPhone(phone: string): Promise<{ expiresIn: number }> {
  const allowed = await checkOtpRateLimit(phone);
  if (!allowed) {
    throw new Error('RATE_LIMIT_EXCEEDED');
  }

  const otp = generateOtp();
  await storeOtp(phone, otp);
  await sendOtpSms(phone, otp);

  return { expiresIn: 300 };
}

export async function verifyOtpAndLogin(phone: string, otp: string) {
  const isValid = await verifyOtp(phone, otp);
  if (!isValid) {
    throw new Error('AUTH_INVALID_OTP');
  }

  let user = await prisma.user.findUnique({
    where: { phone },
    include: {
      userRoles: {
        include: { role: true },
      },
    },
  });

  if (!user) {
    user = await prisma.user.create({
      data: {
        phone,
        fullName: 'New User',
        isActive: true,
      },
      include: {
        userRoles: {
          include: { role: true },
        },
      },
    });
  }

  if (!user.isActive) {
    throw new Error('ACCOUNT_DEACTIVATED');
  }

  const roles = user.userRoles.map((ur) => ur.role.name);

  const accessToken = generateAccessToken({ userId: user.id, roles });
  const refreshToken = await generateRefreshToken(user.id);

  return {
    accessToken,
    refreshToken,
    user: {
      id: user.id,
      fullName: user.fullName,
      roles,
    },
  };
}

export async function refreshAccessToken(refreshTokenStr: string) {
  const payload = await verifyRefreshToken(refreshTokenStr);
  if (!payload) {
    throw new Error('AUTH_TOKEN_EXPIRED');
  }

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

  if (!user || !user.isActive) {
    throw new Error('AUTH_TOKEN_EXPIRED');
  }

  const roles = user.userRoles.map((ur) => ur.role.name);

  const accessToken = generateAccessToken({ userId: user.id, roles });

  await revokeRefreshToken(refreshTokenStr);
  const newRefreshToken = await generateRefreshToken(user.id);

  return {
    accessToken,
    refreshToken: newRefreshToken,
  };
}

export async function getCurrentUser(userId: string) {
  const user = await prisma.user.findUnique({
    where: { id: userId },
    include: {
      userRoles: {
        include: {
          role: true,
          school: { select: { id: true, name: true } },
        },
      },
    },
  });

  if (!user) {
    throw new Error('RESOURCE_NOT_FOUND');
  }

  return {
    id: user.id,
    phone: user.phone,
    email: user.email,
    fullName: user.fullName,
    profilePhotoUrl: user.profilePhotoUrl,
    isActive: user.isActive,
    roles: user.userRoles.map((ur) => ({
      role: ur.role.name,
      portalType: ur.role.portalType,
      school: ur.school ? { id: ur.school.id, name: ur.school.name } : null,
    })),
    createdAt: user.createdAt.toISOString(),
  };
}
