import { NextResponse } from 'next/server';

import { withAuth, withPermission } from '@/lib/api/helpers';
import { uploadExternallySignedEoi } from '@/lib/services/external-eoi.service';
import { errorResponse, ForbiddenError, NotFoundError, ValidationError } from '@/lib/errors';

export const POST = withAuth(
  withPermission('documents', 'upload_signed', async (req, ctx, params) => {
    try {
      const interestId = params.id;
      if (!interestId) throw new NotFoundError('Interest');

      // Defense-in-depth: uploading an externally-signed EOI mutates
      // the interest's effective state (flips it to "signed"). Require
      // interests.edit in addition to documents.upload_signed so a
      // custom role with the upload bit but no interest-edit can't flip
      // an interest. Super-admin bypasses (audit R2-M6).
      if (!ctx.isSuperAdmin && !ctx.permissions?.interests?.edit) {
        throw new ForbiddenError('interests.edit required to upload an external EOI');
      }

      const form = await req.formData();
      const file = form.get('file');
      if (!file || !(file instanceof File)) {
        throw new ValidationError('Missing file');
      }
      const buffer = Buffer.from(await file.arrayBuffer());

      const title = (form.get('title') as string | null) ?? undefined;
      const notes = (form.get('notes') as string | null) ?? undefined;
      const signerNamesRaw = (form.get('signerNames') as string | null) ?? '';
      const signerNames = signerNamesRaw
        ? signerNamesRaw
            .split(',')
            .map((s) => s.trim())
            .filter(Boolean)
        : undefined;
      // Newer clients post a structured `signatories` JSON array. Parse
      // safely and ignore malformed payloads (downstream falls back to
      // signerNames).
      const signatoriesRaw = (form.get('signatories') as string | null) ?? null;
      let signatories:
        | Array<{
            name: string;
            email: string;
            role: 'client' | 'developer' | 'rep' | 'witness' | 'cc';
          }>
        | undefined;
      if (signatoriesRaw) {
        try {
          const parsed = JSON.parse(signatoriesRaw) as unknown;
          if (Array.isArray(parsed)) {
            signatories = parsed
              .map((row) => {
                if (typeof row !== 'object' || row === null) return null;
                const r = row as Record<string, unknown>;
                if (typeof r.name !== 'string' || typeof r.email !== 'string') return null;
                const role = typeof r.role === 'string' ? r.role : 'client';
                if (!['client', 'developer', 'rep', 'witness', 'cc'].includes(role)) return null;
                return {
                  name: r.name.trim(),
                  email: r.email.trim(),
                  role: role as 'client' | 'developer' | 'rep' | 'witness' | 'cc',
                };
              })
              .filter((s): s is NonNullable<typeof s> => s !== null && !!s.name && !!s.email);
          }
        } catch {
          // ignore malformed JSON
        }
      }
      const signedAtRaw = (form.get('signedAt') as string | null) ?? null;
      const signedAt = signedAtRaw ? new Date(signedAtRaw) : undefined;
      if (signedAt && Number.isNaN(signedAt.getTime())) {
        throw new ValidationError('Invalid signedAt');
      }

      const cancelActiveDocumentIdRaw =
        (form.get('cancelActiveDocumentId') as string | null) ?? null;
      const cancelActiveDocumentId = cancelActiveDocumentIdRaw?.trim() || undefined;

      // Which signed doc this is. Defaults to 'eoi' (legacy callers); the
      // reservation/contract tabs post their own type so it files correctly.
      const docTypeRaw = (form.get('docType') as string | null)?.trim() ?? 'eoi';
      const docType = (
        ['eoi', 'reservation', 'contract'].includes(docTypeRaw) ? docTypeRaw : 'eoi'
      ) as 'eoi' | 'reservation' | 'contract';

      const result = await uploadExternallySignedEoi({
        interestId,
        portId: ctx.portId,
        fileData: {
          buffer,
          originalName: file.name,
          mimeType: file.type || 'application/pdf',
          size: file.size,
        },
        title,
        signedAt,
        signerNames,
        signatories,
        notes,
        cancelActiveDocumentId,
        docType,
        meta: {
          userId: ctx.userId,
          portId: ctx.portId,
          ipAddress: ctx.ipAddress,
          userAgent: ctx.userAgent,
        },
      });

      return NextResponse.json({ data: result });
    } catch (error) {
      return errorResponse(error);
    }
  }),
);
