import { NextResponse } from 'next/server';

import { withAuth, withPermission } from '@/lib/api/helpers';
import { parseBody } from '@/lib/api/route-helpers';
import { errorResponse, ValidationError } from '@/lib/errors';
import {
  generateBrochureStorageKey,
  registerBrochureVersion,
} from '@/lib/services/brochures.service';
import { registerBrochureVersionSchema } from '@/lib/validators/brochures';

/**
 * Two-step upload (per §11.1):
 *   1. GET (no body) - server returns a fresh storage key + presigned URL.
 *   2. POST (metadata) - after the browser PUTs to the URL, register the
 *      version row server-side.
 *
 * Direct-to-storage uploads bypass Next.js's body-size limit; the server
 * never holds the 20MB+ payload in memory.
 */
import { getStorageBackend } from '@/lib/storage';
import { getSalesContentConfig } from '@/lib/services/sales-email-config.service';

export const GET = withAuth(
  withPermission('admin', 'manage_settings', async (_req, ctx, params) => {
    try {
      const id = params.id!;
      const content = await getSalesContentConfig(ctx.portId);
      const storageKey = await generateBrochureStorageKey(ctx.portId, id);
      const maxBytes = content.brochureMaxUploadMb * 1024 * 1024;
      const storage = await getStorageBackend();
      const { url } = await storage.presignUpload(storageKey, {
        expirySeconds: 900,
        contentType: 'application/pdf',
        // Bind the token to the port (engages the filesystem proxy `p`
        // port-namespace assertion) - audit L22.
        portSlug: ctx.portSlug,
        // Embed the per-port cap so the filesystem proxy PUT enforces the
        // advertised brochure cap rather than the global 50 MB - audit M17.
        maxBytes,
      });
      return NextResponse.json({
        data: {
          storageKey,
          uploadUrl: url,
          method: 'PUT',
          maxBytes,
        },
      });
    } catch (error) {
      return errorResponse(error);
    }
  }),
);

// Storage keys generated by `generateBrochureStorageKey` look like
// `<portSlug>/brochures/<brochureId>/<uuid>.pdf`. Reject anything else -
// without this, an admin holding manage_settings on port A could ship a
// foreign port's storage key (signed EOI bytes, another port's brochure)
// and have registerBrochureVersion repoint THIS port's brochure version
// at confidential bytes that subsequently serve under brochures.view.
const BROCHURE_KEY_RE =
  /^[a-z0-9-]+\/brochures\/[A-Za-z0-9_-]+\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.pdf$/;

export const POST = withAuth(
  withPermission('admin', 'manage_settings', async (req, ctx, params) => {
    try {
      const id = params.id!;
      const input = await parseBody(req, registerBrochureVersionSchema);
      if (!BROCHURE_KEY_RE.test(input.storageKey)) {
        throw new ValidationError('storageKey is not in the expected brochure path');
      }
      const segments = input.storageKey.split('/');
      // segments: [portSlug, 'brochures', brochureId, '<uuid>.pdf']
      if (segments[2] !== id) {
        throw new ValidationError('storageKey brochureId does not match route param');
      }
      const data = await registerBrochureVersion({
        portId: ctx.portId,
        brochureId: id,
        storageKey: input.storageKey,
        fileName: input.fileName,
        fileSizeBytes: input.fileSizeBytes,
        contentSha256: input.contentSha256,
        uploadedBy: ctx.userId,
      });
      return NextResponse.json({ data }, { status: 201 });
    } catch (error) {
      return errorResponse(error);
    }
  }),
);
