import { generateToken, hash256 } from '@blitzjs/auth'
import { resolver } from '@blitzjs/rpc'
import db from 'db'
import { forgotPasswordMailer } from 'mailers/forgotPasswordMailer'
import { ForgotPassword } from '../schemas'

const RESET_PASSWORD_TOKEN_EXPIRATION_IN_HOURS = 4

export default resolver.pipe(
  resolver.zod(ForgotPassword),
  async ({ email }) => {
    // 1. Get the user
    const user = await db.user.findFirst({
      where: { email: email.toLowerCase() },
    })

    // 2. Generate the token and expiration date.
    const token = generateToken()
    const hashedToken = hash256(token)
    const expiresAt = new Date()
    expiresAt.setHours(
      expiresAt.getHours() + RESET_PASSWORD_TOKEN_EXPIRATION_IN_HOURS
    )

    // 3. If user with this email was found
    if (user) {
      // 4. Delete any existing password reset tokens
      await db.token.deleteMany({
        where: { type: 'RESET_PASSWORD', userId: user.id },
      })
      // 5. Save this new token in the database.
      await db.token.create({
        data: {
          user: { connect: { id: user.id } },
          type: 'RESET_PASSWORD',
          expiresAt,
          hashedToken,
          sentTo: user.email,
        },
      })
      // 6. Send the email
      await forgotPasswordMailer({ to: user.email, token }).send()
    } else {
      // 7. If no user found wait the same time so attackers can't tell the difference
      await new Promise((resolve) => setTimeout(resolve, 750))
    }

    // 8. Return the same result whether a password reset email was sent or not
    return
  }
)
