import path from 'path'
import multer from 'multer'
import { ValidationError } from '../errors'

const MAX_FILE_SIZE = 10 * 1024 * 1024 // 10 MB
const ALLOWED_IMAGE_TYPES = new Map<string, string[]>([
  ['image/jpeg', ['.jpg', '.jpeg']],
  ['image/png', ['.png']],
  ['image/webp', ['.webp']],
  ['image/gif', ['.gif']],
])

/**
 * Shared multer instance used by all upload endpoints.
 * Files are kept in memory so services receive a Buffer — no temp-file cleanup needed.
 */
export const imageUpload = multer({
  storage: multer.memoryStorage(),
  limits: { fileSize: MAX_FILE_SIZE, files: 20 },
})

type DetectedFile = { mime: string; ext: string }

export function detectImageType(buffer: Buffer): DetectedFile | null {
  if (buffer.length >= 3 && buffer[0] === 0xff && buffer[1] === 0xd8 && buffer[2] === 0xff) {
    return { mime: 'image/jpeg', ext: '.jpg' }
  }

  if (
    buffer.length >= 8 &&
    buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4e && buffer[3] === 0x47 &&
    buffer[4] === 0x0d && buffer[5] === 0x0a && buffer[6] === 0x1a && buffer[7] === 0x0a
  ) {
    return { mime: 'image/png', ext: '.png' }
  }

  if (buffer.length >= 12 && buffer.subarray(0, 4).toString('ascii') === 'RIFF' && buffer.subarray(8, 12).toString('ascii') === 'WEBP') {
    return { mime: 'image/webp', ext: '.webp' }
  }

  if (buffer.length >= 6) {
    const sig = buffer.subarray(0, 6).toString('ascii')
    if (sig === 'GIF87a' || sig === 'GIF89a') return { mime: 'image/gif', ext: '.gif' }
  }

  return null
}

function assertSafeImageContent(file: Express.Multer.File) {
  const detected = detectImageType(file.buffer)
  if (!detected || !ALLOWED_IMAGE_TYPES.has(detected.mime)) {
    throw new ValidationError(`Unsupported or spoofed image file: ${file.originalname}`)
  }

  if (file.mimetype !== detected.mime) {
    throw new ValidationError(`MIME type does not match file content for "${file.originalname}"`)
  }

  const ext = path.extname(file.originalname).toLowerCase()
  const allowedExtensions = ALLOWED_IMAGE_TYPES.get(detected.mime) ?? []
  if (ext && !allowedExtensions.includes(ext)) {
    throw new ValidationError(`File extension does not match file content for "${file.originalname}"`)
  }
}

/**
 * Asserts that a file was provided and is an image by content, not by client claims.
 */
export function assertImageFile(
  file: Express.Multer.File | undefined,
  fieldLabel = 'file',
): asserts file is Express.Multer.File {
  if (!file) throw new ValidationError(`A ${fieldLabel} is required`)
  assertSafeImageContent(file)
}

/**
 * Asserts that at least one file was provided and all files are image content.
 */
export function assertImageFiles(files: Express.Multer.File[], fieldLabel = 'photos'): void {
  if (!files || files.length === 0) throw new ValidationError(`At least one ${fieldLabel} file is required`)
  for (const file of files) assertSafeImageContent(file)
}
