/**
 * Magic-byte sniff for POST /uploads. Extension and client Content-Type
 * are not trusted — only the file body decides whether we accept it and
 * which extension we persist.
 */

export type UploadedKind = 'image' | 'video' | 'pdf';

export interface SniffedUpload {
  ext: string;
  kind: UploadedKind;
  mime: string;
}

export const ALLOWED_UPLOAD_EXTENSIONS = [
  '.jpg',
  '.jpeg',
  '.png',
  '.gif',
  '.webp',
  '.ico',
  '.mp4',
  '.mov',
  '.webm',
  '.avi',
  '.pdf',
] as const;

export type AllowedUploadExtension = (typeof ALLOWED_UPLOAD_EXTENSIONS)[number];

const ALLOWED_EXT_SET = new Set<string>(ALLOWED_UPLOAD_EXTENSIONS);

export function isAllowedUploadExtension(ext: string): ext is AllowedUploadExtension {
  return ALLOWED_EXT_SET.has(ext.toLowerCase());
}

function ascii(body: Buffer, start: number, end: number): string {
  return body.toString('ascii', start, end);
}

/**
 * Returns the sniffed type, or null when the body is not a permitted
 * image / video / PDF. SVG/HTML/polyglots that fail these signatures
 * are rejected.
 */
export function sniffUpload(body: Buffer): SniffedUpload | null {
  if (!body || body.length < 12) return null;

  if (body[0] === 0xff && body[1] === 0xd8 && body[2] === 0xff) {
    return { ext: '.jpg', kind: 'image', mime: 'image/jpeg' };
  }

  if (body[0] === 0x89 && body[1] === 0x50 && body[2] === 0x4e && body[3] === 0x47) {
    return { ext: '.png', kind: 'image', mime: 'image/png' };
  }

  if (body[0] === 0x47 && body[1] === 0x49 && body[2] === 0x46 && body[3] === 0x38) {
    return { ext: '.gif', kind: 'image', mime: 'image/gif' };
  }

  if (ascii(body, 0, 4) === 'RIFF' && ascii(body, 8, 12) === 'WEBP') {
    return { ext: '.webp', kind: 'image', mime: 'image/webp' };
  }

  if (ascii(body, 0, 4) === 'RIFF' && ascii(body, 8, 12) === 'AVI ') {
    return { ext: '.avi', kind: 'video', mime: 'video/x-msvideo' };
  }

  if (body[0] === 0x00 && body[1] === 0x00 && body[2] === 0x01 && body[3] === 0x00) {
    return { ext: '.ico', kind: 'image', mime: 'image/x-icon' };
  }

  if (ascii(body, 0, 4) === '%PDF') {
    return { ext: '.pdf', kind: 'pdf', mime: 'application/pdf' };
  }

  if (body[0] === 0x1a && body[1] === 0x45 && body[2] === 0xdf && body[3] === 0xa3) {
    return { ext: '.webm', kind: 'video', mime: 'video/webm' };
  }

  if (ascii(body, 4, 8) === 'ftyp') {
    const brand = ascii(body, 8, 12);
    if (brand.startsWith('qt')) {
      return { ext: '.mov', kind: 'video', mime: 'video/quicktime' };
    }
    return { ext: '.mp4', kind: 'video', mime: 'video/mp4' };
  }

  return null;
}

const PAN_DOCUMENT_EXTENSIONS = new Set(['.jpg', '.jpeg', '.png', '.gif', '.webp', '.pdf']);

export function isAllowedPanExtension(ext: string): boolean {
  return PAN_DOCUMENT_EXTENSIONS.has(ext.toLowerCase());
}

/** PAN cards: images and PDF only — never video or icon files. */
export function sniffPanDocument(body: Buffer): SniffedUpload | null {
  const sniffed = sniffUpload(body);
  if (!sniffed || !isAllowedPanExtension(sniffed.ext)) return null;
  return sniffed;
}
