import "server-only";
import { createHash } from "node:crypto";
import { promises as fs } from "node:fs";
import path from "node:path";
import sharp from "sharp";

const MAX_BYTES = 6 * 1024 * 1024;
const ALLOWED_MIME = new Set([
  "image/jpeg",
  "image/png",
  "image/webp",
  "image/gif",
]);

export type AvatarSaveResult =
  | { ok: true; path: string; width: number; height: number }
  | { ok: false; error: string };

/**
 * Save + normalise an uploaded avatar file. Produces a 512×512 WebP centred
 * crop, written to `/public/uploads/avatars/YYYY-MM/<sha>.webp`. Public-facing
 * code uses the returned `path` as the `<img src>`. Safe to call with a File
 * that's `undefined` or zero bytes — it returns `{ ok: false }` in that case.
 */
export async function saveAvatarUpload(file: unknown): Promise<AvatarSaveResult> {
  if (!(file instanceof File)) return { ok: false, error: "no file" };
  if (file.size === 0) return { ok: false, error: "empty file" };
  if (file.size > MAX_BYTES) {
    return { ok: false, error: `Image is too large (max ${MAX_BYTES / 1024 / 1024} MB).` };
  }
  if (!ALLOWED_MIME.has(file.type)) {
    return { ok: false, error: `Unsupported image type: ${file.type || "unknown"}` };
  }

  const buffer = Buffer.from(await file.arrayBuffer());
  const sha = createHash("sha256").update(buffer).digest("hex").slice(0, 16);
  const now = new Date();
  const bucket = `${now.getUTCFullYear()}-${String(now.getUTCMonth() + 1).padStart(2, "0")}`;
  const dir = path.join(process.cwd(), "public", "uploads", "avatars", bucket);
  await fs.mkdir(dir, { recursive: true });
  const filename = `${sha}.webp`;
  const abs = path.join(dir, filename);

  try {
    const pipeline = sharp(buffer, { failOn: "none" })
      .rotate()
      .resize(512, 512, { fit: "cover", position: "centre" })
      .webp({ quality: 85 });
    const info = await pipeline.toFile(abs);
    return {
      ok: true,
      path: `/uploads/avatars/${bucket}/${filename}`,
      width: info.width,
      height: info.height,
    };
  } catch (err) {
    console.error("[avatar] processing failed", err);
    return { ok: false, error: "Failed to process image." };
  }
}
