import { NextResponse } from 'next/server';
import { z } from 'zod';
import { and, asc, eq } from 'drizzle-orm';

import { withAuth, withPermission } from '@/lib/api/helpers';
import { parseBody } from '@/lib/api/route-helpers';
import { db } from '@/lib/db';
import { documents, documentSigners } from '@/lib/db/schema/documents';
import { ports } from '@/lib/db/schema/ports';
import {
  sendSigningInvitation,
  type SignerRole,
} from '@/lib/services/document-signing-emails.service';
import { getPortDocumensoConfig } from '@/lib/services/port-config';
import { errorResponse, NotFoundError, ValidationError } from '@/lib/errors';

const bodySchema = z.object({
  /** Optional — defaults to the next pending signer in signing-order. */
  recipientId: z.string().optional(),
});

const DOC_TYPE_LABEL: Record<
  string,
  'Expression of Interest' | 'Sales Contract' | 'Reservation Agreement'
> = {
  eoi: 'Expression of Interest',
  contract: 'Sales Contract',
  reservation_agreement: 'Reservation Agreement',
};

/**
 * Send a branded signing-invitation email to a specific recipient
 * (defaults to the next-pending signer in signing-order). Used by:
 *   - The auto-send path when port `eoi_send_mode = 'auto'`
 *   - The "Send invitation" button in the EOI/Contract tab when
 *     `eoi_send_mode = 'manual'`
 *   - The cascading-email logic on DOCUMENT_SIGNED webhooks
 */
export const POST = withAuth(
  withPermission('documents', 'send_for_signing', async (req, ctx, params) => {
    try {
      const documentId = params.id;
      if (!documentId) throw new NotFoundError('Document');
      const body = await parseBody(req, bodySchema);

      const doc = await db.query.documents.findFirst({
        where: and(eq(documents.id, documentId), eq(documents.portId, ctx.portId)),
      });
      if (!doc) throw new NotFoundError('Document');

      const signers = await db
        .select()
        .from(documentSigners)
        .where(eq(documentSigners.documentId, documentId))
        .orderBy(asc(documentSigners.signingOrder));

      const target = body.recipientId
        ? signers.find((s) => s.id === body.recipientId)
        : signers.find((s) => s.status === 'pending');
      if (!target) {
        throw new ValidationError('No pending signer found to invite');
      }
      if (!target.signingUrl) {
        throw new ValidationError(
          'Signer has no Documenso URL yet — generate or send the document first',
        );
      }

      const port = await db.query.ports.findFirst({ where: eq(ports.id, ctx.portId) });
      const docCfg = await getPortDocumensoConfig(ctx.portId);

      await sendSigningInvitation({
        portId: ctx.portId,
        portName: port?.name ?? 'Port Nimara',
        recipient: { name: target.signerName, email: target.signerEmail },
        documensoSigningUrl: target.signingUrl,
        documentLabel: DOC_TYPE_LABEL[doc.documentType] ?? 'Expression of Interest',
        signerRole: (target.signerRole as SignerRole) ?? 'client',
        senderName: docCfg.developerName ?? null,
      });

      await db
        .update(documentSigners)
        .set({ invitedAt: new Date() })
        .where(eq(documentSigners.id, target.id));

      return NextResponse.json({ data: { recipientId: target.id, sent: true } });
    } catch (error) {
      return errorResponse(error);
    }
  }),
);
