"use server";

/**
 * Server actions for chart CRUD + share token management.
 *
 * Mounting:
 *   - <SaveChartButton> on /tu-vi-tron-doi calls saveChartAction
 *   - /la-so renders chart list (server component) and uses these for
 *     edit/delete/toggle-share inline forms
 */
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { prisma } from "@/lib/db";
import { currentUser, newShareToken, inputToPersist } from "@/lib/charts";
import type { ChartInput } from "@/lib/tuvi/engine";

const MAX_LABEL_LEN = 80;

type SaveResult = { ok: true; id: string; isNew: boolean } | { ok: false; error: string };

/** Save (or update) a chart from a ChartInput + label. If id is supplied,
 *  updates that row (label only — input is treated as immutable). */
export async function saveChartAction(
  input: ChartInput,
  label: string,
  existingId?: string
): Promise<SaveResult> {
  const user = await currentUser();
  if (!user) return { ok: false, error: "Cần đăng nhập để lưu lá số" };

  const cleanLabel = label.trim().slice(0, MAX_LABEL_LEN) || "Lá số";

  if (existingId) {
    const before = await prisma.chart.findFirst({
      where: { id: existingId, userId: user.id },
      select: { id: true },
    });
    if (!before) return { ok: false, error: "Không tìm thấy lá số" };
    await prisma.chart.update({
      where: { id: before.id },
      data: { label: cleanLabel },
    });
    revalidatePath("/la-so");
    return { ok: true, id: before.id, isNew: false };
  }

  // Count existing — first chart auto-becomes default.
  const count = await prisma.chart.count({ where: { userId: user.id } });
  const persisted = inputToPersist(input, cleanLabel);
  const created = await prisma.chart.create({
    data: {
      ...persisted,
      userId: user.id,
      isDefault: count === 0,
    },
    select: { id: true },
  });
  revalidatePath("/la-so");
  return { ok: true, id: created.id, isNew: true };
}

/** Delete a chart owned by current user. */
export async function deleteChartAction(formData: FormData): Promise<void> {
  const user = await currentUser();
  if (!user) redirect("/login");
  const id = String(formData.get("id") ?? "");
  if (!id) return;
  await prisma.chart.deleteMany({ where: { id, userId: user.id } });
  revalidatePath("/la-so");
}

/** Toggle share token: enabling mints a new token, disabling clears it. */
export async function toggleShareAction(formData: FormData): Promise<void> {
  const user = await currentUser();
  if (!user) redirect("/login");
  const id = String(formData.get("id") ?? "");
  if (!id) return;

  const chart = await prisma.chart.findFirst({
    where: { id, userId: user.id },
    select: { id: true, shareToken: true },
  });
  if (!chart) return;

  if (chart.shareToken) {
    await prisma.chart.update({ where: { id }, data: { shareToken: null } });
  } else {
    // Loop on collision (extremely unlikely with 128-bit token, but cheap).
    for (let attempt = 0; attempt < 5; attempt += 1) {
      const token = newShareToken();
      try {
        await prisma.chart.update({ where: { id }, data: { shareToken: token } });
        break;
      } catch (e) {
        if (attempt === 4) throw e;
      }
    }
  }
  revalidatePath("/la-so");
}

/** Mark a different chart as the user's default. Useful when default is the
 *  one auto-loaded by the dashboard / van-menh. */
export async function setDefaultAction(formData: FormData): Promise<void> {
  const user = await currentUser();
  if (!user) redirect("/login");
  const id = String(formData.get("id") ?? "");
  if (!id) return;
  // Within a transaction: clear all defaults for this user, set the target.
  await prisma.$transaction([
    prisma.chart.updateMany({ where: { userId: user.id }, data: { isDefault: false } }),
    prisma.chart.updateMany({ where: { id, userId: user.id }, data: { isDefault: true } }),
  ]);
  revalidatePath("/la-so");
}

/** Rename a chart (label only). */
export async function renameChartAction(formData: FormData): Promise<void> {
  const user = await currentUser();
  if (!user) redirect("/login");
  const id = String(formData.get("id") ?? "");
  const label = String(formData.get("label") ?? "")
    .trim()
    .slice(0, MAX_LABEL_LEN);
  if (!id || !label) return;
  await prisma.chart.updateMany({
    where: { id, userId: user.id },
    data: { label },
  });
  revalidatePath("/la-so");
}
