import { logger } from '@/lib/logger';

type AllowedMimeType =
  | 'application/pdf'
  | 'image/jpeg'
  | 'image/png'
  | 'image/gif'
  | 'image/webp';

type SniffResult =
  | { mime: AllowedMimeType; reason?: string }
  | { mime: null; reason: string };

const SIGNATURES: Record<AllowedMimeType, (buffer: Buffer) => boolean> = {
  'application/pdf': (buffer) => buffer.subarray(0, 4).toString('utf8') === '%PDF',
  'image/jpeg': (buffer) => buffer[0] === 0xff && buffer[1] === 0xd8 && buffer[2] === 0xff,
  'image/png': (buffer) => buffer.subarray(0, 8).equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a])),
  'image/gif': (buffer) => buffer.subarray(0, 4).toString('utf8') === 'GIF8',
  'image/webp': (buffer) => buffer.subarray(0, 4).toString('utf8') === 'RIFF' && buffer.subarray(8, 12).toString('utf8') === 'WEBP',
};

/**
 * Sniff MIME type using magic numbers to prevent spoofed uploads.
 */
export function sniffMimeFromBuffer(buffer: Buffer): SniffResult {
  for (const [mime, matcher] of Object.entries(SIGNATURES) as Array<[AllowedMimeType, (buffer: Buffer) => boolean]>) {
    if (matcher(buffer)) {
      return { mime };
    }
  }

  return { mime: null, reason: 'Unrecognized or unsupported file signature' };
}

/**
 * Basic PDF heuristic used for resume/contact uploads.
 * Returns a string describing the issue or null when the file looks safe.
 */
export function scanPdfBufferForThreats(buffer: Buffer): string | null {
  if (!SIGNATURES['application/pdf'](buffer)) {
    return 'File is not a valid PDF';
  }

  // Inspect a small sample for embedded scripts/JavaScript actions
  const sample = buffer.toString('utf8', 0, Math.min(buffer.length, 8192));
  if (/[<]script/i.test(sample) || /\/(JS|JavaScript)/i.test(sample)) {
    return 'PDF contains embedded script content and was rejected';
  }

  return null;
}

/**
 * Lightweight heuristic for common polyglot/script injection attempts in uploads.
 */
export function detectSuspiciousContent(buffer: Buffer, mime: AllowedMimeType): string | null {
  if (mime === 'application/pdf') {
    return scanPdfBufferForThreats(buffer);
  }

  // For images, peek at the first couple KB for obvious script markers
  const sample = buffer.toString('utf8', 0, Math.min(buffer.length, 2048));
  if (/<script|<iframe|<svg/i.test(sample) || /javascript:/i.test(sample) || /<\?php/i.test(sample)) {
    return 'Attachment includes embedded script-like content and was rejected';
  }

  return null;
}

export type ValidatedFile =
  | {
      ok: true;
      buffer: Buffer;
      mime: AllowedMimeType;
      declaredType: string;
      name: string;
      size: number;
    }
  | { ok: false; error: string };

/**
 * Validate uploaded file size, sniff MIME type, and return a buffer for further checks.
 */
export async function validateAndPrepareFile(
  file: File,
  allowedMimeTypes: ReadonlySet<string>,
  maxSizeBytes: number
): Promise<ValidatedFile> {
  if (file.size > maxSizeBytes) {
    return { ok: false, error: `File "${file.name}" exceeds the allowed size of ${Math.floor(maxSizeBytes / (1024 * 1024))}MB` };
  }

  const buffer = Buffer.from(await file.arrayBuffer());
  const sniffed = sniffMimeFromBuffer(buffer);

  if (!sniffed.mime) {
    return { ok: false, error: sniffed.reason };
  }

  if (!allowedMimeTypes.has(sniffed.mime)) {
    return { ok: false, error: `File content type ${sniffed.mime} is not allowed` };
  }

  if (file.type && file.type !== sniffed.mime) {
    logger.warn('Upload MIME mismatch detected', {
      declared: file.type,
      sniffed: sniffed.mime,
      fileName: file.name,
    });
    return { ok: false, error: `File "${file.name}" content does not match its declared type` };
  }

  return {
    ok: true,
    buffer,
    mime: sniffed.mime,
    declaredType: file.type || 'unknown',
    name: file.name,
    size: file.size,
  };
}
