/**
 * /api/brands/[brandId]/assets
 *
 * GET  — list BrandAsset rows for a brand (auto-seeds the brand logo
 *        from BrandProfile.logoUrl on first access).
 * POST — upload a PNG or JPEG image (multipart form data). Saves to
 *        public/uploads/<brandId>/ and extracts dimensions via
 *        image-size before creating the BrandAsset row.
 *
 * All routes are auth-gated by org membership.
 */

import { NextResponse } from "next/server";
import { promises as fs } from "fs";
import path from "path";
import { randomBytes } from "crypto";
import { imageSize } from "image-size";
import sharp from "sharp";
import { getCurrentUser } from "@/lib/auth";
import { prisma } from "@/lib/prisma";

export const dynamic = "force-dynamic";
export const maxDuration = 60;

const ALLOWED_MIME = new Set(["image/png", "image/jpeg"]);
const MAX_FILE_BYTES = 10 * 1024 * 1024; // 10 MB
const ALLOWED_TYPES = new Set(["logo", "photo", "icon", "background"]);

async function resolveBrand(brandId: string, userId: string) {
  const brand = await prisma.brand.findUnique({
    where: { id: brandId },
    include: {
      organization: { include: { memberships: true } },
      profile: { select: { logoUrl: true } },
    },
  });
  if (!brand) return { error: "Brand not found" as const, status: 404 };
  if (!brand.organization.memberships.some((m) => m.userId === userId)) {
    return { error: "Access denied" as const, status: 403 };
  }
  return { brand };
}

/** One-time seed: if the brand profile has a logoUrl but no BrandAsset
 *  of type="logo" exists yet, create one so the image library surfaces
 *  it at the top automatically. */
async function ensureLogoAsset(brandId: string, logoUrl: string | null | undefined) {
  if (!logoUrl) return;
  const existing = await prisma.brandAsset.findFirst({ where: { brandId, type: "logo" } });
  if (existing) return;
  try {
    await prisma.brandAsset.create({
      data: {
        brandId,
        filename: "Brand logo",
        url: logoUrl,
        type: "logo",
        mimeType: /\.png(\?|$)/i.test(logoUrl) ? "image/png" : "image/jpeg",
        fileSize: 0,
        tags: ["auto-imported"],
      },
    });
  } catch {
    // Swallow — the logo column might contain an unsupported format; the
    // user can always re-upload through the normal flow.
  }
}

// ─── GET ────────────────────────────────────────────────────────────────────────────────

export async function GET(req: Request, { params }: { params: { brandId: string } }) {
  const user = await getCurrentUser();
  if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });

  const resolved = await resolveBrand(params.brandId, user.id);
  if ("error" in resolved) return NextResponse.json({ error: resolved.error }, { status: resolved.status });

  await ensureLogoAsset(params.brandId, resolved.brand.profile?.logoUrl ?? null);

  const { searchParams } = new URL(req.url);
  const typeFilter = searchParams.get("type");
  const where: { brandId: string; type?: string } = { brandId: params.brandId };
  if (typeFilter && ALLOWED_TYPES.has(typeFilter)) where.type = typeFilter;

  const assets = await prisma.brandAsset.findMany({
    where,
    orderBy: [{ type: "asc" }, { uploadedAt: "desc" }],
  });

  // Sort logos first, then by uploadedAt desc
  assets.sort((a, b) => {
    if (a.type === "logo" && b.type !== "logo") return -1;
    if (a.type !== "logo" && b.type === "logo") return 1;
    return b.uploadedAt.getTime() - a.uploadedAt.getTime();
  });

  return NextResponse.json({ assets });
}

// ─── POST ─────────────────────────────────────────────────────────────────────────────────

export async function POST(req: Request, { params }: { params: { brandId: string } }) {
  const user = await getCurrentUser();
  if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });

  const resolved = await resolveBrand(params.brandId, user.id);
  if ("error" in resolved) return NextResponse.json({ error: resolved.error }, { status: resolved.status });

  let formData: FormData;
  try {
    formData = await req.formData();
  } catch {
    return NextResponse.json({ error: "Invalid form data" }, { status: 400 });
  }

  const file = formData.get("file");
  if (!file || !(file instanceof File)) {
    return NextResponse.json({ error: "No file provided" }, { status: 400 });
  }

  // ── Server-side validation (MIME + size) ──
  if (!ALLOWED_MIME.has(file.type)) {
    return NextResponse.json({ error: "Only PNG and JPG images are allowed" }, { status: 400 });
  }
  if (file.size > MAX_FILE_BYTES) {
    return NextResponse.json({ error: "File exceeds 10MB limit" }, { status: 400 });
  }

  const rawType = String(formData.get("type") || "photo");
  const assetType = ALLOWED_TYPES.has(rawType) ? rawType : "photo";
  const altText = String(formData.get("altText") || "");
  const tagsRaw = String(formData.get("tags") || "");
  const tags = tagsRaw ? tagsRaw.split(",").map((t) => t.trim()).filter(Boolean) : [];

  // ── Read input bytes ──
  const inputBuffer = Buffer.from(await file.arrayBuffer());

  // ── Sharp resize: max 512px on longest edge, normalize to PNG ──
  let resizedBuffer: Buffer;
  try {
    resizedBuffer = await sharp(inputBuffer)
      .resize(512, 512, {
        fit: "inside",           // preserve aspect ratio, longest edge ≤ 512px
        withoutEnlargement: true, // don't upscale images already under 512px
      })
      .toFormat("png", { quality: 90 })
      .toBuffer();
  } catch {
    return NextResponse.json(
      { error: "Unable to process image. Use a standard PNG or JPEG." },
      { status: 400 },
    );
  }

  console.log(
    `[brand-assets] resize: ${params.brandId} ${Math.round(inputBuffer.byteLength / 1024)}KB → ${Math.round(resizedBuffer.byteLength / 1024)}KB`,
  );

  // ── Write file to public/uploads/<brandId>/ ──
  // Always .png output since Sharp normalizes to PNG regardless of input format.
  const safeBase = path.basename(file.name, path.extname(file.name)).replace(/[^a-zA-Z0-9._-]+/g, "-").slice(0, 60) || "image";
  const uniq = randomBytes(6).toString("hex");
  const storedFilename = `${safeBase}-${uniq}.png`;

  const uploadDir = path.join(process.cwd(), "public", "uploads", params.brandId);
  await fs.mkdir(uploadDir, { recursive: true });
  const fullPath = path.join(uploadDir, storedFilename);
  await fs.writeFile(fullPath, resizedBuffer);

  // ── Dimension extraction from resized output (best-effort) ──
  let width: number | undefined;
  let height: number | undefined;
  try {
    const dims = imageSize(resizedBuffer);
    width = dims.width;
    height = dims.height;
  } catch {
    /* ignore — dimensions are non-essential */
  }

  const publicUrl = `/uploads/${params.brandId}/${storedFilename}`;

  const asset = await prisma.brandAsset.create({
    data: {
      brandId: params.brandId,
      filename: file.name.slice(0, 200),
      url: publicUrl,
      type: assetType,
      mimeType: "image/png",
      fileSize: resizedBuffer.byteLength,
      width,
      height,
      altText: altText || null,
      tags,
    },
  });

  return NextResponse.json({ asset });
}
