// Local upload service. Files go into /public/uploads with a random
// filename so callers cannot collide or overwrite each other. Returns
// the public URL (relative path) that the question record stores.

import { writeFile, mkdir } from 'fs/promises';
import { existsSync } from 'fs';
import path from 'path';
import crypto from 'crypto';
import { HttpError } from '@/lib/auth/session';

const UPLOAD_DIR = path.join(process.cwd(), 'public', 'uploads');
const ALLOWED = ['image/png', 'image/jpeg', 'image/webp', 'image/gif'];
const MAX_BYTES = 5 * 1024 * 1024; // 5 MB

export const uploadService = {
  async saveImage(file: File): Promise<{ url: string }> {
    if (!ALLOWED.includes(file.type)) {
      throw new HttpError(415, 'Only PNG, JPG, WEBP, or GIF images are allowed');
    }
    if (file.size > MAX_BYTES) {
      throw new HttpError(413, 'Image must be smaller than 5 MB');
    }

    if (!existsSync(UPLOAD_DIR)) {
      await mkdir(UPLOAD_DIR, { recursive: true });
    }

    // crypto.randomUUID gives us collision-resistant filenames without
    // pulling in another dependency.
    const ext = extensionFor(file.type);
    const filename = `${crypto.randomUUID()}${ext}`;
    const filepath = path.join(UPLOAD_DIR, filename);

    const buffer = Buffer.from(await file.arrayBuffer());
    await writeFile(filepath, buffer);

    return { url: `/uploads/${filename}` };
  },
};

function extensionFor(mime: string): string {
  switch (mime) {
    case 'image/png': return '.png';
    case 'image/jpeg': return '.jpg';
    case 'image/webp': return '.webp';
    case 'image/gif': return '.gif';
    default: return '';
  }
}
