import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
import { verifyEmbeddingPresignToken } from '@documenso/lib/server-only/embedding-presign/verify-embedding-presign-token';
import { createEnvelope } from '@documenso/lib/server-only/envelope/create-envelope';
import { mapSecondaryIdToTemplateId } from '@documenso/lib/utils/envelope';
import { prisma } from '@documenso/prisma';
import { EnvelopeType } from '@prisma/client';

import { procedure } from '../trpc';
import {
  ZCreateEmbeddingTemplateRequestSchema,
  ZCreateEmbeddingTemplateResponseSchema,
} from './create-embedding-template.types';

// Todo: Envelopes - This only supports V1 documents/templates.
export const createEmbeddingTemplateRoute = procedure
  .input(ZCreateEmbeddingTemplateRequestSchema)
  .output(ZCreateEmbeddingTemplateResponseSchema)
  .mutation(async ({ input, ctx: { req, metadata } }) => {
    try {
      const authorizationHeader = req.headers.get('authorization');

      const [presignToken] = (authorizationHeader || '').split('Bearer ').filter((s) => s.length > 0);

      if (!presignToken) {
        throw new AppError(AppErrorCode.UNAUTHORIZED, {
          message: 'No presign token provided',
        });
      }

      const apiToken = await verifyEmbeddingPresignToken({ token: presignToken });

      const { title, documentDataId, recipients, meta } = input;

      // First create the template
      const template = await createEnvelope({
        internalVersion: 1,
        userId: apiToken.userId,
        teamId: apiToken.teamId ?? undefined,
        data: {
          type: EnvelopeType.TEMPLATE,
          title,
          envelopeItems: [
            {
              documentDataId,
            },
          ],
        },
        meta,
        requestMetadata: metadata,
      });

      const firstEnvelopeItem = template.envelopeItems[0];

      await Promise.all(
        recipients.map(async (recipient) => {
          const createdRecipient = await prisma.recipient.create({
            data: {
              envelopeId: template.id,
              email: recipient.email,
              name: recipient.name || '',
              role: recipient.role || 'SIGNER',
              token: `template-${template.id}-${recipient.email}`,
              signingOrder: recipient.signingOrder,
            },
          });

          const fields = recipient.fields ?? [];

          const createdFields = await prisma.field.createMany({
            data: fields.map((field) => ({
              envelopeId: template.id,
              envelopeItemId: firstEnvelopeItem.id,
              recipientId: createdRecipient.id,
              type: field.type,
              page: field.pageNumber,
              positionX: field.pageX,
              positionY: field.pageY,
              width: field.width,
              height: field.height,
              customText: '',
              inserted: false,
            })),
          });

          return {
            ...createdRecipient,
            fields: createdFields,
          };
        }),
      );

      if (!template.id) {
        throw new AppError(AppErrorCode.UNKNOWN_ERROR, {
          message: 'Failed to create template: missing template ID',
        });
      }

      return {
        templateId: mapSecondaryIdToTemplateId(template.secondaryId),
      };
    } catch (error) {
      if (error instanceof AppError) {
        throw error;
      }

      throw new AppError(AppErrorCode.UNKNOWN_ERROR, {
        message: 'Failed to create template',
      });
    }
  });
