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 { canManageHumanCapital } from "@/lib/human-capital";

const HUMAN_CAPITAL_FILES_UPLOAD_DIR =
  process.env.HUMAN_CAPITAL_FILES_UPLOAD_DIR?.trim() || "/tmp/casa-benell/uploads/human-capital-files";
const HUMAN_CAPITAL_FILES_PUBLIC_PREFIX = "/api/human-capital/files/assets";
const MAX_UPLOAD_BYTES = 12 * 1024 * 1024;

const ALLOWED_MIME_TO_EXT = {
  "application/pdf": "pdf",
  "image/jpeg": "jpg",
  "image/png": "png",
  "image/webp": "webp",
  "application/msword": "doc",
  "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx",
  "application/vnd.ms-excel": "xls",
  "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlsx",
  "text/plain": "txt",
} 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) {
      return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
    }

    if (!canManageHumanCapital(session.user.role, session.user.department)) {
      return NextResponse.json({ error: "Only owner/HC leaders can upload files." }, { status: 403 });
    }

    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_UPLOAD_BYTES) {
      return NextResponse.json({ error: "file exceeds 12 MB limit." }, { status: 400 });
    }

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

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

    const filename = buildStoredFilename(fileValue.type);
    const absolutePath = path.join(HUMAN_CAPITAL_FILES_UPLOAD_DIR, filename);
    const bytes = Buffer.from(await fileValue.arrayBuffer());

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

    return NextResponse.json({
      ok: true,
      fileUrl: `${HUMAN_CAPITAL_FILES_PUBLIC_PREFIX}/${filename}`,
      fileName: filename,
      mimeType: fileValue.type,
      sizeBytes: fileValue.size,
    });
  } catch (error) {
    if (createdFilePath) {
      await unlink(createdFilePath).catch(() => {
        // ignore cleanup failures
      });
    }

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