"use server";

import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { writeFile, mkdir } from "fs/promises";
import path from "path";
import crypto from "crypto";
import { prisma } from "@/lib/prisma";
import { slugify } from "@/lib/slug";
import { requirePermission } from "@/lib/permissions";
import { parseCsv, csvRowsToObjects } from "@/lib/csv";

const ALLOWED_IMAGE_TYPES: Record<string, string> = {
  "image/jpeg": "jpg",
  "image/png": "png",
  "image/webp": "webp",
  "image/gif": "gif",
};
const MAX_IMAGE_SIZE = 5 * 1024 * 1024;

function parseImagesInput(raw: string): string[] {
  return raw
    .split(/[\n,]/)
    .map((s) => s.trim())
    .filter(Boolean);
}

function productDataFromForm(formData: FormData) {
  const name = String(formData.get("name") ?? "").trim();
  const description = String(formData.get("description") ?? "").trim();
  const priceRupees = Number(formData.get("basePrice") ?? 0);
  const categoryId = String(formData.get("categoryId") ?? "");
  const imagesRaw = String(formData.get("images") ?? "");
  const personalizable = formData.get("personalizable") === "on";
  const active = formData.get("active") === "on";
  const minOrderQtyRaw = Number(formData.get("minOrderQty") ?? 1);
  const minOrderQty = Number.isFinite(minOrderQtyRaw) ? Math.max(1, Math.round(minOrderQtyRaw)) : 1;

  if (!name || !categoryId || !Number.isFinite(priceRupees) || priceRupees <= 0) {
    throw new Error("Name, category, and a valid price are required");
  }

  const images = parseImagesInput(imagesRaw);

  return {
    name,
    description,
    basePrice: Math.round(priceRupees * 100),
    categoryId,
    images: JSON.stringify(images.length ? images : ["https://placehold.co/600x600/fda4af/7c2d12.png?text=" + encodeURIComponent(name)]),
    personalizable,
    active,
    minOrderQty,
  };
}

export async function createProduct(formData: FormData) {
  await requirePermission("products", "add");
  const data = productDataFromForm(formData);
  const baseSlug = slugify(data.name);
  let slug = baseSlug;
  let n = 1;
  while (await prisma.product.findUnique({ where: { slug } })) {
    slug = `${baseSlug}-${++n}`;
  }

  const product = await prisma.product.create({ data: { ...data, slug } });
  revalidatePath("/iv-manage-84x2/products");
  revalidatePath("/shop");
  revalidatePath("/");
  redirect(`/iv-manage-84x2/products/${product.id}?success=Product+added.`);
}

function truthy(value: string | undefined): boolean {
  return ["yes", "true", "1", "y"].includes((value ?? "").trim().toLowerCase());
}

export async function bulkCreateProducts(formData: FormData) {
  await requirePermission("products", "add");

  const file = formData.get("file");
  if (!(file instanceof File) || file.size === 0) {
    redirect("/iv-manage-84x2/products/bulk?error=Choose+a+CSV+file+first");
  }

  const text = await (file as File).text();
  const rows = csvRowsToObjects(parseCsv(text));
  if (rows.length === 0) {
    redirect("/iv-manage-84x2/products/bulk?error=That+file+has+no+data+rows");
  }

  const categories = await prisma.category.findMany({ select: { id: true, name: true } });
  const categoryByName = new Map(categories.map((c) => [c.name.trim().toLowerCase(), c.id]));

  let created = 0;
  const errors: string[] = [];

  for (let i = 0; i < rows.length; i++) {
    const rowNum = i + 2; // +1 for header, +1 for 1-indexing
    const row = rows[i];
    const name = (row.name ?? "").trim();
    const priceRaw = (row.price ?? "").trim();
    const categoryName = (row.category ?? "").trim();

    if (!name) {
      errors.push(`Row ${rowNum}: missing name`);
      continue;
    }
    const priceRupees = Number(priceRaw);
    if (!priceRaw || Number.isNaN(priceRupees) || priceRupees <= 0) {
      errors.push(`Row ${rowNum} (${name}): missing or invalid price`);
      continue;
    }
    const categoryId = categoryByName.get(categoryName.toLowerCase());
    if (!categoryId) {
      errors.push(`Row ${rowNum} (${name}): category "${categoryName}" doesn't exist`);
      continue;
    }

    const baseSlug = slugify(name);
    let slug = baseSlug;
    let n = 1;
    while (await prisma.product.findUnique({ where: { slug } })) {
      slug = `${baseSlug}-${++n}`;
    }

    const minOrderQty = Math.max(1, Math.round(Number(row.minorderqty)) || 1);

    await prisma.product.create({
      data: {
        name,
        slug,
        description: (row.description ?? "").trim(),
        basePrice: Math.round(priceRupees * 100),
        categoryId,
        images: JSON.stringify(["https://placehold.co/600x600/fda4af/7c2d12.png?text=" + encodeURIComponent(name)]),
        personalizable: truthy(row.personalizable),
        active: truthy(row.active),
        minOrderQty,
      },
    });
    created++;
  }

  revalidatePath("/iv-manage-84x2/products");
  revalidatePath("/shop");
  revalidatePath("/");

  const params = new URLSearchParams();
  params.set("created", String(created));
  params.set("failed", String(errors.length));
  if (errors.length > 0) params.set("errors", errors.slice(0, 15).join("|"));
  redirect(`/iv-manage-84x2/products/bulk?${params.toString()}`);
}

export async function updateProduct(id: string, formData: FormData) {
  await requirePermission("products", "edit");
  const data = productDataFromForm(formData);
  await prisma.product.update({ where: { id }, data });
  revalidatePath("/iv-manage-84x2/products");
  revalidatePath("/shop");
  revalidatePath("/");
  redirect(`/iv-manage-84x2/products/${id}?success=Product+saved.`);
}

export async function updateMinOrderQty(id: string, formData: FormData) {
  await requirePermission("products", "edit");
  const minOrderQtyRaw = Number(formData.get("minOrderQty") ?? 1);
  if (!Number.isFinite(minOrderQtyRaw)) redirect("/iv-manage-84x2/products?error=Enter+a+valid+quantity");
  const minOrderQty = Math.max(1, Math.round(minOrderQtyRaw));
  await prisma.product.update({ where: { id }, data: { minOrderQty } });
  revalidatePath("/iv-manage-84x2/products");
  redirect("/iv-manage-84x2/products?success=Minimum+order+quantity+updated.");
}

export async function updateBasePrice(id: string, formData: FormData) {
  await requirePermission("products", "edit");
  const priceRupeesRaw = Number(formData.get("basePrice") ?? 0);
  if (!Number.isFinite(priceRupeesRaw)) redirect("/iv-manage-84x2/products?error=Enter+a+valid+price");
  const priceRupees = Math.max(0.01, priceRupeesRaw);
  await prisma.product.update({ where: { id }, data: { basePrice: Math.round(priceRupees * 100) } });
  revalidatePath("/iv-manage-84x2/products");
  revalidatePath("/shop");
  revalidatePath("/");
  redirect("/iv-manage-84x2/products?success=Price+updated.");
}

export async function updateProductName(id: string, formData: FormData) {
  await requirePermission("products", "edit");
  const name = String(formData.get("name") ?? "").trim();
  if (!name) redirect("/iv-manage-84x2/products?error=Name+can%27t+be+empty");
  await prisma.product.update({ where: { id }, data: { name } });
  revalidatePath("/iv-manage-84x2/products");
  revalidatePath("/shop");
  revalidatePath("/");
  redirect("/iv-manage-84x2/products?success=Product+name+updated.");
}

export async function updateProductCategory(id: string, formData: FormData) {
  await requirePermission("products", "edit");
  const categoryId = String(formData.get("categoryId") ?? "");
  if (!categoryId) redirect("/iv-manage-84x2/products?error=Pick+a+category");
  await prisma.product.update({ where: { id }, data: { categoryId } });
  revalidatePath("/iv-manage-84x2/products");
  revalidatePath("/shop");
  revalidatePath("/");
  redirect("/iv-manage-84x2/products?success=Product+category+updated.");
}

export async function updateProductImage(id: string, formData: FormData) {
  await requirePermission("products", "edit");
  const file = formData.get("image");
  if (!(file instanceof File) || file.size === 0) redirect("/iv-manage-84x2/products?error=No+image+selected");

  const ext = ALLOWED_IMAGE_TYPES[file.type];
  if (!ext) redirect("/iv-manage-84x2/products?error=Only+JPG%2C+PNG%2C+WEBP%2C+or+GIF+images+are+allowed");
  if (file.size > MAX_IMAGE_SIZE) redirect("/iv-manage-84x2/products?error=Image+must+be+under+5MB");

  const uploadDir = path.join(process.cwd(), "public", "uploads", "products");
  await mkdir(uploadDir, { recursive: true });
  const filename = `${crypto.randomUUID()}.${ext}`;
  const bytes = Buffer.from(await file.arrayBuffer());
  await writeFile(path.join(uploadDir, filename), bytes);

  await prisma.product.update({
    where: { id },
    data: { images: JSON.stringify([`/uploads/products/${filename}`]) },
  });
  revalidatePath("/iv-manage-84x2/products");
  revalidatePath("/shop");
  revalidatePath("/");
  redirect("/iv-manage-84x2/products?success=Product+image+updated.");
}

export async function updatePurchasePrice(id: string, formData: FormData) {
  await requirePermission("inventory", "edit");
  const raw = String(formData.get("purchasePrice") ?? "").trim();
  let purchasePrice: number | null = null;
  if (raw !== "") {
    const rawNum = Number(raw);
    if (!Number.isFinite(rawNum)) redirect("/iv-manage-84x2/stock?error=Enter+a+valid+purchase+price");
    purchasePrice = Math.max(0, Math.round(rawNum * 100));
  }
  await prisma.product.update({ where: { id }, data: { purchasePrice } });
  revalidatePath("/iv-manage-84x2/stock");
  redirect("/iv-manage-84x2/stock?success=Purchase+price+updated.");
}

export async function updateWeight(id: string, formData: FormData) {
  await requirePermission("inventory", "edit");
  const raw = String(formData.get("weightGrams") ?? "").trim();
  let weightGrams: number | null = null;
  if (raw !== "") {
    const rawNum = Number(raw);
    if (!Number.isFinite(rawNum)) redirect("/iv-manage-84x2/stock?error=Enter+a+valid+weight");
    weightGrams = Math.max(0, Math.round(rawNum));
  }
  await prisma.product.update({ where: { id }, data: { weightGrams } });
  revalidatePath("/iv-manage-84x2/stock");
  redirect("/iv-manage-84x2/stock?success=Weight+updated.");
}

export async function updateStockSellingPrice(id: string, formData: FormData) {
  await requirePermission("inventory", "edit");
  const priceRupeesRaw = Number(formData.get("basePrice") ?? 0);
  if (!Number.isFinite(priceRupeesRaw)) redirect("/iv-manage-84x2/stock?error=Enter+a+valid+price");
  const priceRupees = Math.max(0.01, priceRupeesRaw);
  await prisma.product.update({ where: { id }, data: { basePrice: Math.round(priceRupees * 100) } });
  revalidatePath("/iv-manage-84x2/stock");
  revalidatePath("/iv-manage-84x2/products");
  revalidatePath("/shop");
  revalidatePath("/");
  redirect("/iv-manage-84x2/stock?success=Selling+price+updated.");
}

export async function updateSalePrice(id: string, formData: FormData) {
  await requirePermission("discounts", "edit");
  const raw = String(formData.get("salePrice") ?? "").trim();
  let salePrice: number | null = null;
  if (raw !== "") {
    const rawNum = Number(raw);
    if (!Number.isFinite(rawNum)) redirect("/iv-manage-84x2/discounts/products?error=Enter+a+valid+sale+price");
    salePrice = Math.max(0, Math.round(rawNum * 100));
    const product = await prisma.product.findUniqueOrThrow({ where: { id } });
    if (salePrice >= product.basePrice) {
      redirect("/iv-manage-84x2/discounts/products?error=Sale+price+must+be+less+than+the+base+price");
    }
  }
  await prisma.product.update({ where: { id }, data: { salePrice } });
  revalidatePath("/iv-manage-84x2/discounts");
  revalidatePath("/iv-manage-84x2/products");
  revalidatePath("/shop");
  revalidatePath("/");
  redirect("/iv-manage-84x2/discounts/products?success=Sale+price+updated.");
}

export async function updateStock(id: string, formData: FormData) {
  await requirePermission("inventory", "edit");
  const raw = String(formData.get("stock") ?? "").trim();
  let stock: number | null = null;
  if (raw !== "") {
    const rawNum = Number(raw);
    if (!Number.isFinite(rawNum)) redirect("/iv-manage-84x2/stock?error=Enter+a+valid+stock+quantity");
    stock = Math.max(0, Math.round(rawNum));
  }
  await prisma.product.update({ where: { id }, data: { stock } });
  revalidatePath("/iv-manage-84x2/stock");
  revalidatePath("/shop");
  revalidatePath("/");
  redirect("/iv-manage-84x2/stock?success=Stock+updated.");
}

export async function deleteProduct(id: string) {
  await requirePermission("products", "delete");
  await prisma.product.delete({ where: { id } });
  revalidatePath("/iv-manage-84x2/products");
  revalidatePath("/shop");
  redirect("/iv-manage-84x2/products?success=Product+deleted.");
}

export async function addVariant(productId: string, formData: FormData) {
  await requirePermission("products", "add");
  const name = String(formData.get("name") ?? "").trim();
  const priceDeltaRupees = Number(formData.get("priceDelta") ?? 0);
  const stock = Math.max(0, Number(formData.get("stock") ?? 0));
  const sku = String(formData.get("sku") ?? "").trim() || null;

  if (!name) redirect(`/iv-manage-84x2/products/${productId}?error=Variant+name+is+required`);

  await prisma.productVariant.create({
    data: { productId, name, priceDelta: Math.round(priceDeltaRupees * 100), stock, sku },
  });
  revalidatePath(`/iv-manage-84x2/products/${productId}`);
  redirect(`/iv-manage-84x2/products/${productId}?success=Variant+added.`);
}

export async function deleteVariant(id: string, productId: string) {
  await requirePermission("products", "delete");
  await prisma.productVariant.delete({ where: { id } });
  revalidatePath(`/iv-manage-84x2/products/${productId}`);
  redirect(`/iv-manage-84x2/products/${productId}?success=Variant+deleted.`);
}
