import { NextResponse } from 'next/server';
import { eq } from 'drizzle-orm';

import { withAuth, withPermission } from '@/lib/api/helpers';
import { db } from '@/lib/db';
import { ports } from '@/lib/db/schema/ports';
import { uploadFile } from '@/lib/services/files';
import { errorResponse, ValidationError } from '@/lib/errors';

const MAX_BYTES = 5 * 1024 * 1024;

/**
 * Image upload for branding settings (logo, email banner, etc).
 * Accepts a multipart `file` (cropped JPEG/PNG/WebP from the
 * ImageCropperDialog) and returns a stable URL that the settings
 * form stores as a `string` value on `system_settings`.
 *
 * The URL points at `/api/v1/files/<id>/preview` so swapping the
 * storage backend (S3 ↔ filesystem) carries the asset transparently.
 */
export const POST = withAuth(
  withPermission('admin', 'manage_settings', async (req, ctx) => {
    try {
      const formData = await req.formData();
      const fileEntry = formData.get('file');
      if (!(fileEntry instanceof File)) {
        throw new ValidationError('Missing `file` part');
      }
      if (fileEntry.size === 0) {
        throw new ValidationError('Empty file');
      }
      if (fileEntry.size > MAX_BYTES) {
        throw new ValidationError('Image exceeds 5 MB');
      }

      const port = ctx.portId
        ? await db.query.ports.findFirst({ where: eq(ports.id, ctx.portId) })
        : null;
      if (!port) throw new ValidationError('No active port');

      const buffer = Buffer.from(await fileEntry.arrayBuffer());
      // Pick the storage filename's extension from the upload's MIME so
      // PNG uploads aren't silently relabelled `.jpg` (the previous
      // hardcoded extension flattened alpha-transparent logos).
      const mimeType = fileEntry.type || 'image/jpeg';
      const ext =
        mimeType === 'image/png'
          ? 'png'
          : mimeType === 'image/webp'
            ? 'webp'
            : mimeType === 'image/gif'
              ? 'gif'
              : mimeType === 'image/avif'
                ? 'avif'
                : 'jpg';
      const record = await uploadFile(
        port.id,
        port.slug,
        {
          buffer,
          originalName: fileEntry.name || `branding.${ext}`,
          mimeType,
          size: fileEntry.size,
        },
        {
          filename: `branding-${Date.now()}.${ext}`,
          category: 'branding',
          entityType: 'port',
          entityId: port.id,
        },
        {
          userId: ctx.userId,
          portId: port.id,
          ipAddress: ctx.ipAddress,
          userAgent: ctx.userAgent,
        },
      );

      // Path-only so the in-app `<img src>` resolves against whatever
      // host the page was loaded from (localhost, LAN IP, prod domain).
      // Email shell calls `absolutizeBrandingUrl()` to prepend APP_URL
      // for mail clients, which have no origin context.
      const url = `/api/public/files/${record.id}`;

      return NextResponse.json({ data: { fileId: record.id, url } });
    } catch (error) {
      return errorResponse(error);
    }
  }),
);
