import { NextApiRequest, NextApiResponse } from 'next';

import { randomUUID } from 'crypto';

import { hashSync } from '@documenso/lib/server-only/auth/hash';
import { redis } from '@documenso/lib/server-only/redis';
import { stripe } from '@documenso/lib/server-only/stripe';
import { prisma } from '@documenso/prisma';

import { TClaimPlanResponseSchema, ZClaimPlanRequestSchema } from '~/api/claim-plan/types';

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse<TClaimPlanResponseSchema>,
) {
  try {
    const { method } = req;

    if (method?.toUpperCase() !== 'POST') {
      return res.status(405).json({
        error: 'Method not allowed',
      });
    }

    const safeBody = ZClaimPlanRequestSchema.safeParse(req.body);

    if (!safeBody.success) {
      return res.status(400).json({
        error: 'Bad request',
      });
    }

    const { email, name, planId, signatureDataUrl, signatureText } = safeBody.data;

    const user = await prisma.user.findFirst({
      where: {
        email: email.toLowerCase(),
      },
      include: {
        Subscription: true,
      },
    });

    if (user && user.Subscription.length > 0) {
      return res.status(200).json({
        // eslint-disable-next-line turbo/no-undeclared-env-vars
        redirectUrl: `${process.env.NEXT_PUBLIC_APP_URL}/login`,
      });
    }

    const password = Math.random().toString(36).slice(2, 9);
    const passwordHash = hashSync(password);

    const { id: userId } = await prisma.user.upsert({
      where: {
        email: email.toLowerCase(),
      },
      create: {
        email: email.toLowerCase(),
        name,
        password: passwordHash,
      },
      update: {
        name,
        password: passwordHash,
      },
    });

    await redis.set(`user:${userId}:temp-password`, password, {
      // expire in 24 hours
      ex: 60 * 60 * 24,
    });

    const signatureDataUrlKey = randomUUID();

    if (signatureDataUrl) {
      await redis.set(`signature:${signatureDataUrlKey}`, signatureDataUrl, {
        // expire in 7 days
        ex: 60 * 60 * 24 * 7,
      });
    }

    const metadata: Record<string, string> = {
      name,
      email,
      signatureText: signatureText || name,
      source: 'landing',
    };

    if (signatureDataUrl) {
      metadata.signatureDataUrl = signatureDataUrlKey;
    }

    const checkout = await stripe.checkout.sessions.create({
      customer_email: email,
      client_reference_id: userId.toString(),
      payment_method_types: ['card'],
      line_items: [
        {
          price: planId,
          quantity: 1,
        },
      ],
      mode: 'subscription',
      metadata,
      allow_promotion_codes: true,
      // eslint-disable-next-line turbo/no-undeclared-env-vars
      success_url: `${process.env.NEXT_PUBLIC_SITE_URL}/claimed?sessionId={CHECKOUT_SESSION_ID}`,
      cancel_url: `${process.env.NEXT_PUBLIC_SITE_URL}/pricing?email=${encodeURIComponent(
        email,
      )}&name=${encodeURIComponent(name)}&planId=${planId}&cancelled=true`,
    });

    if (!checkout.url) {
      throw new Error('Checkout URL not found');
    }

    return res.json({
      redirectUrl: checkout.url,
    });
  } catch (error) {
    console.error(error);

    return res.status(500).json({
      error: 'Internal server error',
    });
  }
}
