"use server";

import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { eq } from "drizzle-orm";
import { z } from "zod";
import { db } from "@/lib/db/client";
import { storeCategories, storeProducts } from "@/lib/db/schema";
import { requireAdmin } from "@/lib/auth/admin-guard";
import { logAdminAction } from "@/lib/audit";

function slugify(input: string): string {
  return input
    .toLowerCase()
    .trim()
    .replace(/[^a-z0-9\s-]/g, "")
    .replace(/\s+/g, "-")
    .replace(/-+/g, "-")
    .slice(0, 80);
}

async function ensureAdmin() {
  const session = await requireAdmin();
  return (session.user as { id?: string }).id!;
}

// -------------------------------------------------------------------------
// Categories
// -------------------------------------------------------------------------

const createCategorySchema = z.object({
  name: z.string().min(1).max(120),
  description: z.string().max(500).optional(),
});

export async function createCategory(formData: FormData) {
  const adminId = await ensureAdmin();
  const parsed = createCategorySchema.parse({
    name: formData.get("name"),
    description: formData.get("description") ?? "",
  });

  let slug = slugify(parsed.name) || "category";
  const [existing] = await db
    .select({ id: storeCategories.id })
    .from(storeCategories)
    .where(eq(storeCategories.slug, slug))
    .limit(1);
  if (existing) slug = `${slug}-${Math.random().toString(36).slice(2, 6)}`;

  const siblings = await db.select({ id: storeCategories.id }).from(storeCategories);

  const [row] = await db
    .insert(storeCategories)
    .values({
      slug,
      name: parsed.name,
      description: parsed.description ?? "",
      position: siblings.length,
    })
    .returning({ id: storeCategories.id });

  await logAdminAction({
    adminUserId: adminId,
    action: "create_store_category",
    targetId: row.id,
  });

  revalidatePath("/admin/store");
  revalidatePath("/products/store");
}

const renameCategorySchema = z.object({
  id: z.string().uuid(),
  name: z.string().min(1).max(120),
  description: z.string().max(500),
});

export async function renameCategory(formData: FormData) {
  const adminId = await ensureAdmin();
  const parsed = renameCategorySchema.parse({
    id: formData.get("id"),
    name: formData.get("name") ?? "",
    description: formData.get("description") ?? "",
  });

  await db
    .update(storeCategories)
    .set({
      name: parsed.name,
      description: parsed.description,
      updatedAt: new Date(),
    })
    .where(eq(storeCategories.id, parsed.id));

  await logAdminAction({
    adminUserId: adminId,
    action: "update_store_category",
    targetId: parsed.id,
  });

  revalidatePath("/admin/store");
  revalidatePath("/products/store");
}

export async function deleteCategory(formData: FormData) {
  const adminId = await ensureAdmin();
  const id = z.string().uuid().parse(formData.get("id"));
  await db.delete(storeCategories).where(eq(storeCategories.id, id));
  await logAdminAction({
    adminUserId: adminId,
    action: "delete_store_category",
    targetId: id,
  });
  revalidatePath("/admin/store");
  revalidatePath("/products/store");
}

// -------------------------------------------------------------------------
// Products
// -------------------------------------------------------------------------

const productStatusValues = ["draft", "published", "archived"] as const;
const stockStatusValues = ["in_stock", "out_of_stock", "preorder", "coming_soon"] as const;

const createProductSchema = z.object({
  title: z.string().min(3).max(200),
  shortDescription: z.string().max(400).optional(),
  categoryId: z.string().uuid().or(z.literal("")).optional(),
  priceMinor: z.coerce.number().int().min(0).max(1_000_000),
});

export async function createProduct(formData: FormData) {
  const adminId = await ensureAdmin();
  const parsed = createProductSchema.parse({
    title: formData.get("title"),
    shortDescription: formData.get("shortDescription") ?? "",
    categoryId: (formData.get("categoryId") as string) ?? "",
    priceMinor: formData.get("priceMinor") ?? 0,
  });

  let slug = slugify(parsed.title) || "product";
  const [existing] = await db
    .select({ id: storeProducts.id })
    .from(storeProducts)
    .where(eq(storeProducts.slug, slug))
    .limit(1);
  if (existing) slug = `${slug}-${Math.random().toString(36).slice(2, 6)}`;

  const [row] = await db
    .insert(storeProducts)
    .values({
      slug,
      title: parsed.title,
      shortDescription: parsed.shortDescription ?? "",
      categoryId: parsed.categoryId ? parsed.categoryId : null,
      priceMinor: parsed.priceMinor,
    })
    .returning({ id: storeProducts.id });

  await logAdminAction({
    adminUserId: adminId,
    action: "create_store_product",
    targetId: row.id,
  });

  revalidatePath("/admin/store");
  redirect(`/admin/store/${row.id}`);
}

const updateProductSchema = z.object({
  id: z.string().uuid(),
  title: z.string().min(3).max(200),
  shortDescription: z.string().max(400),
  description: z.string().max(10_000),
  categoryId: z.string().uuid().or(z.literal("")),
  priceMinor: z.coerce.number().int().min(0).max(1_000_000),
  currency: z.string().min(3).max(6),
  sku: z.string().max(120),
  stockStatus: z.enum(stockStatusValues),
  coverImage: z.string().max(400),
  coverImageAlt: z.string().max(400),
  memberOnly: z.string().optional(),
  gallery: z.string().max(20_000).optional(),
});

const gallerySchema = z.object({
  path: z.string().trim().max(500).default(""),
  alt: z.string().trim().max(500).default(""),
});

export async function updateProduct(formData: FormData) {
  const adminId = await ensureAdmin();
  const parsed = updateProductSchema.parse({
    id: formData.get("id"),
    title: formData.get("title") ?? "",
    shortDescription: formData.get("shortDescription") ?? "",
    description: formData.get("description") ?? "",
    categoryId: (formData.get("categoryId") as string) ?? "",
    priceMinor: formData.get("priceMinor") ?? 0,
    currency: formData.get("currency") ?? "GBP",
    sku: formData.get("sku") ?? "",
    stockStatus: formData.get("stockStatus") ?? "coming_soon",
    coverImage: formData.get("coverImage") ?? "",
    coverImageAlt: formData.get("coverImageAlt") ?? "",
    memberOnly: (formData.get("memberOnly") as string) ?? undefined,
    gallery: (formData.get("gallery") as string) ?? "",
  });

  let gallery: Array<{ path: string; alt: string }> = [];
  if (parsed.gallery && parsed.gallery.length > 0) {
    try {
      const raw = JSON.parse(parsed.gallery);
      const result = z.array(gallerySchema).safeParse(raw);
      if (result.success) {
        gallery = result.data.filter((g) => g.path.length > 0);
      }
    } catch {
      gallery = [];
    }
  }

  await db
    .update(storeProducts)
    .set({
      title: parsed.title,
      shortDescription: parsed.shortDescription,
      description: parsed.description,
      categoryId: parsed.categoryId ? parsed.categoryId : null,
      priceMinor: parsed.priceMinor,
      currency: parsed.currency,
      sku: parsed.sku || null,
      stockStatus: parsed.stockStatus,
      coverImage: parsed.coverImage || null,
      coverImageAlt: parsed.coverImageAlt || null,
      memberOnly: parsed.memberOnly === "on",
      gallery,
      updatedAt: new Date(),
    })
    .where(eq(storeProducts.id, parsed.id));

  await logAdminAction({
    adminUserId: adminId,
    action: "update_store_product",
    targetId: parsed.id,
  });

  revalidatePath("/admin/store");
  revalidatePath(`/admin/store/${parsed.id}`);
  revalidatePath("/products/store");
}

const setProductStatusSchema = z.object({
  id: z.string().uuid(),
  status: z.enum(productStatusValues),
});

export async function setProductStatus(formData: FormData) {
  const adminId = await ensureAdmin();
  const parsed = setProductStatusSchema.parse({
    id: formData.get("id"),
    status: formData.get("status"),
  });

  await db
    .update(storeProducts)
    .set({
      status: parsed.status,
      publishedAt: parsed.status === "published" ? new Date() : null,
      updatedAt: new Date(),
    })
    .where(eq(storeProducts.id, parsed.id));

  await logAdminAction({
    adminUserId: adminId,
    action: `store_product_${parsed.status}`,
    targetId: parsed.id,
  });

  revalidatePath("/admin/store");
  revalidatePath(`/admin/store/${parsed.id}`);
  revalidatePath("/products/store");
}

export async function deleteProduct(formData: FormData) {
  const adminId = await ensureAdmin();
  const id = z.string().uuid().parse(formData.get("id"));
  await db.delete(storeProducts).where(eq(storeProducts.id, id));
  await logAdminAction({
    adminUserId: adminId,
    action: "delete_store_product",
    targetId: id,
  });
  revalidatePath("/admin/store");
  revalidatePath("/products/store");
  redirect("/admin/store");
}
