import { randomUUID } from "crypto";
import { mkdir, unlink, writeFile } from "fs/promises";
import path from "path";
import { NextResponse } from "next/server";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
import { prisma } from "@/lib/prisma";

const ACCOUNT_AVATAR_UPLOAD_DIR = process.env.ACCOUNT_AVATAR_UPLOAD_DIR?.trim() || "/tmp/casa-benell/uploads/avatars";
const ACCOUNT_AVATAR_PUBLIC_PREFIX = "/api/account/avatar";
const MAX_AVATAR_BYTES = 5 * 1024 * 1024;

const ALLOWED_MIME_TO_EXT = {
  "image/jpeg": "jpg",
  "image/png": "png",
  "image/webp": "webp",
} as const;

type AllowedMimeType = keyof typeof ALLOWED_MIME_TO_EXT;
function isUploadLikeFile(value: FormDataEntryValue | null): value is File {
  if (!value || typeof value === "string") {
    return false;
  }

  const candidate = value as Partial<File>;
  return typeof candidate.size === "number" && typeof candidate.type === "string" && typeof candidate.arrayBuffer === "function";
}

function isAllowedMimeType(mimeType: string): mimeType is AllowedMimeType {
  return Object.prototype.hasOwnProperty.call(ALLOWED_MIME_TO_EXT, mimeType);
}

function buildStoredFilename(mimeType: AllowedMimeType): string {
  return `${randomUUID()}.${ALLOWED_MIME_TO_EXT[mimeType]}`;
}

export async function POST(request: Request) {
  let createdFilePath: string | null = null;

  try {
    const session = await getServerSession(authOptions);
    if (!session?.user?.id) {
      return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
    }

    const formData = await request.formData();
    const fileValue = formData.get("file");

    if (!isUploadLikeFile(fileValue)) {
      return NextResponse.json({ error: "file is required." }, { status: 400 });
    }

    if (fileValue.size <= 0) {
      return NextResponse.json({ error: "file is empty." }, { status: 400 });
    }

    if (fileValue.size > MAX_AVATAR_BYTES) {
      return NextResponse.json({ error: "file exceeds 5 MB limit." }, { status: 400 });
    }

    if (!isAllowedMimeType(fileValue.type)) {
      return NextResponse.json({ error: "Unsupported file type." }, { status: 400 });
    }

    await mkdir(ACCOUNT_AVATAR_UPLOAD_DIR, { recursive: true });

    const filename = buildStoredFilename(fileValue.type);
    const absolutePath = path.join(ACCOUNT_AVATAR_UPLOAD_DIR, filename);
    const imageUrl = `${ACCOUNT_AVATAR_PUBLIC_PREFIX.replace(/\/$/, "")}/${filename}`;
    const bytes = Buffer.from(await fileValue.arrayBuffer());

    const existingUser = await prisma.user.findUnique({
      where: { id: session.user.id },
      select: { image: true },
    });

    await writeFile(absolutePath, bytes);
    createdFilePath = absolutePath;

    await prisma.user.update({
      where: { id: session.user.id },
      data: { image: imageUrl },
    });

    const existingImage = existingUser?.image?.trim() ?? "";
    if (existingImage.startsWith(`${ACCOUNT_AVATAR_PUBLIC_PREFIX}/`)) {
      const oldFileName = path.basename(existingImage.split("?")[0] ?? "");
      if (oldFileName && oldFileName !== filename) {
        await unlink(path.join(ACCOUNT_AVATAR_UPLOAD_DIR, oldFileName)).catch(() => {
          // ignore cleanup failures
        });
      }
    }

    return NextResponse.json({
      ok: true,
      imageUrl,
    });
  } catch (error) {
    if (createdFilePath) {
      await unlink(createdFilePath).catch(() => {
        // ignore cleanup failures
      });
    }

    console.error("account avatar upload failed", error);
    const message = error instanceof Error ? error.message : "Failed to upload avatar.";
    return NextResponse.json({ error: message }, { status: 500 });
  }
}
