import { prisma } from '@documenso/prisma';

import { WebhookTriggerEvents } from '@prisma/client';

import { z } from 'zod';

import { jobs } from '../../jobs/client';

import { extractDerivedDocumentEmailSettings } from '../../types/document-email';

import { mapEnvelopeToWebhookDocumentPayload, ZWebhookDocumentSchema } from '../../types/webhook-payload';

import { sendDocument } from '../document/send-document';

import { incrementDocumentId } from '../envelope/increment-id';

import { triggerWebhook } from '../webhooks/trigger/trigger-webhook';
import { createDirectTemplateEnvelope } from './create-direct-template-envelope';
import type { CreateDocumentFromDirectTemplateOptions } from './direct-template-types';
import { prepareDirectTemplate } from './prepare-direct-template';

export type { CreateDocumentFromDirectTemplateOptions } from './direct-template-types';

export const ZCreateDocumentFromDirectTemplateResponseSchema = z.object({
  token: z.string(),
  envelopeId: z.string(),
  documentId: z.number(),
  recipientId: z.number(),
});

export type TCreateDocumentFromDirectTemplateResponse = z.infer<typeof ZCreateDocumentFromDirectTemplateResponseSchema>;

export const createDocumentFromDirectTemplate = async (
  options: CreateDocumentFromDirectTemplateOptions,
): Promise<TCreateDocumentFromDirectTemplateResponse> => {
  const context = await prepareDirectTemplate(options);
  const incrementedDocumentId = await incrementDocumentId();
  const { createdEnvelope, documentMeta, recipientId, token } = await createDirectTemplateEnvelope(
    context,
    incrementedDocumentId,
  );
  const { requestMetadata } = options;

  const emailSettings = extractDerivedDocumentEmailSettings(documentMeta);

  if (emailSettings.ownerDocumentCreated) {
    await jobs.triggerJob({
      name: 'send.document.created.from.direct.template.email',
      payload: {
        envelopeId: createdEnvelope.id,
        recipientId,
      },
    });
  }

  try {
    // This handles sending emails and sealing the document if required.
    await sendDocument({
      id: {
        type: 'envelopeId',
        id: createdEnvelope.id,
      },
      userId: createdEnvelope.userId,
      teamId: createdEnvelope.teamId,
      requestMetadata,
    });

    // Refetch envelope so we get the final data.
    const refetchedEnvelope = await prisma.envelope.findFirstOrThrow({
      where: {
        id: createdEnvelope.id,
      },
      include: {
        documentMeta: true,
        recipients: true,
      },
    });

    await triggerWebhook({
      event: WebhookTriggerEvents.DOCUMENT_SIGNED,
      data: ZWebhookDocumentSchema.parse(mapEnvelopeToWebhookDocumentPayload(refetchedEnvelope)),
      userId: refetchedEnvelope.userId,
      teamId: refetchedEnvelope.teamId ?? undefined,
    });
  } catch (err) {
    console.error('[CREATE_DOCUMENT_FROM_DIRECT_TEMPLATE]:', err);

    // Don't launch an error since the document has already been created.
    // Log and reseal as required until we configure middleware.
  }

  return {
    token,
    envelopeId: createdEnvelope.id,
    documentId: incrementedDocumentId.documentId,
    recipientId,
  };
};
