import {
  DIRECT_TEMPLATE_RECIPIENT_EMAIL,
  DIRECT_TEMPLATE_RECIPIENT_NAME,
} from '@documenso/lib/constants/direct-templates';
import { prisma } from '@documenso/prisma';
import { EnvelopeType, type Recipient } from '@prisma/client';
import { nanoid } from 'nanoid';

import { AppError, AppErrorCode } from '../../errors/app-error';
import { type EnvelopeIdOptions, mapSecondaryIdToTemplateId } from '../../utils/envelope';
import { getEnvelopeWhereInput } from '../envelope/get-envelope-by-id';

export type CreateTemplateDirectLinkOptions = {
  id: EnvelopeIdOptions;
  userId: number;
  teamId: number;
  directRecipientId?: number;
};

export const createTemplateDirectLink = async ({
  id,
  userId,
  teamId,
  directRecipientId,
}: CreateTemplateDirectLinkOptions) => {
  const { envelopeWhereInput } = await getEnvelopeWhereInput({
    id,
    type: EnvelopeType.TEMPLATE,
    userId,
    teamId,
  });

  const envelope = await prisma.envelope.findFirst({
    where: envelopeWhereInput,
    include: {
      recipients: true,
      directLink: true,
    },
  });

  if (!envelope) {
    throw new AppError(AppErrorCode.NOT_FOUND, { message: 'Template not found' });
  }

  if (envelope.directLink) {
    throw new AppError(AppErrorCode.ALREADY_EXISTS, { message: 'Direct template already exists' });
  }

  if (directRecipientId && !envelope.recipients.find((recipient) => recipient.id === directRecipientId)) {
    throw new AppError(AppErrorCode.NOT_FOUND, { message: 'Recipient not found' });
  }

  if (
    !directRecipientId &&
    envelope.recipients.find((recipient) => recipient.email.toLowerCase() === DIRECT_TEMPLATE_RECIPIENT_EMAIL)
  ) {
    throw new AppError(AppErrorCode.INVALID_BODY, {
      message: 'Cannot generate placeholder direct recipient',
    });
  }

  const createdDirectLink = await prisma.$transaction(async (tx) => {
    let recipient: Recipient | undefined;

    if (directRecipientId) {
      recipient = await tx.recipient.update({
        where: {
          envelopeId: envelope.id,
          id: directRecipientId,
        },
        data: {
          name: DIRECT_TEMPLATE_RECIPIENT_NAME,
          email: DIRECT_TEMPLATE_RECIPIENT_EMAIL,
        },
      });
    } else {
      recipient = await tx.recipient.create({
        data: {
          envelopeId: envelope.id,
          name: DIRECT_TEMPLATE_RECIPIENT_NAME,
          email: DIRECT_TEMPLATE_RECIPIENT_EMAIL,
          token: nanoid(),
        },
      });
    }

    return await tx.templateDirectLink.create({
      data: {
        envelopeId: envelope.id,
        enabled: true,
        token: nanoid(),
        directTemplateRecipientId: recipient.id,
      },
    });
  });

  return {
    id: createdDirectLink.id,
    token: createdDirectLink.token,
    createdAt: createdDirectLink.createdAt,
    enabled: createdDirectLink.enabled,
    directTemplateRecipientId: createdDirectLink.directTemplateRecipientId,
    templateId: mapSecondaryIdToTemplateId(envelope.secondaryId),
    envelopeId: envelope.id,
  };
};
