"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 { consentiqProcedures } 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!;
}

const statusValues = ["draft", "published", "archived"] as const;
const severityValues = ["common", "rare", "serious", ""] as const;
const optionKindValues = ["select", "radio", "text"] as const;

const createSchema = z.object({
  name: z.string().min(3).max(200),
  region: z.string().min(1).max(100),
});

export async function createProcedure(formData: FormData) {
  const adminId = await ensureAdmin();
  const parsed = createSchema.parse({
    name: formData.get("name"),
    region: formData.get("region") ?? "General",
  });

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

  const [row] = await db
    .insert(consentiqProcedures)
    .values({
      slug,
      name: parsed.name,
      region: parsed.region,
    })
    .returning({ id: consentiqProcedures.id });

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

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

const risksSchema = z.array(
  z.object({
    title: z.string().trim().max(200).default(""),
    detail: z.string().trim().max(1000).default(""),
    severity: z.enum(severityValues).default(""),
  }),
);

const optionsSchema = z.array(
  z.object({
    id: z.string().trim().max(60).default(""),
    label: z.string().trim().max(160).default(""),
    kind: z.enum(optionKindValues).default("text"),
    help: z.string().trim().max(400).optional(),
    defaultValue: z.string().trim().max(160).optional(),
    choices: z
      .array(
        z.object({
          value: z.string().trim().max(80).default(""),
          label: z.string().trim().max(160).default(""),
        }),
      )
      .optional(),
  }),
);

function parseJsonArray<T>(raw: unknown, s: z.ZodType<T[]>): T[] {
  if (typeof raw !== "string" || raw.length === 0) return [];
  try {
    const parsed = JSON.parse(raw);
    const result = s.safeParse(parsed);
    return result.success ? result.data : [];
  } catch {
    return [];
  }
}

function multiline(raw: unknown): string[] {
  if (typeof raw !== "string") return [];
  return raw
    .split("\n")
    .map((line) => line.trim())
    .filter(Boolean);
}

const updateSchema = z.object({
  id: z.string().uuid(),
  name: z.string().min(3).max(200),
  region: z.string().min(1).max(100),
  approxDurationMin: z.coerce.number().int().min(0).max(1440),
  anaesthesia: z.string().max(2000),
  summary: z.string().max(4000),
  involves: z.string().max(8000),
  benefits: z.string().max(6000),
  alternatives: z.string().max(6000),
  recovery: z.string().max(6000),
  warnings: z.string().max(6000),
});

export async function updateProcedure(formData: FormData) {
  const adminId = await ensureAdmin();
  const parsed = updateSchema.parse({
    id: formData.get("id"),
    name: formData.get("name") ?? "",
    region: formData.get("region") ?? "",
    approxDurationMin: formData.get("approxDurationMin") ?? 0,
    anaesthesia: formData.get("anaesthesia") ?? "",
    summary: formData.get("summary") ?? "",
    involves: formData.get("involves") ?? "",
    benefits: formData.get("benefits") ?? "",
    alternatives: formData.get("alternatives") ?? "",
    recovery: formData.get("recovery") ?? "",
    warnings: formData.get("warnings") ?? "",
  });

  const risks = parseJsonArray(formData.get("risks"), risksSchema);
  const options = parseJsonArray(formData.get("options"), optionsSchema);

  await db
    .update(consentiqProcedures)
    .set({
      name: parsed.name,
      region: parsed.region,
      approxDurationMin: parsed.approxDurationMin,
      anaesthesia: multiline(parsed.anaesthesia),
      summary: parsed.summary,
      involves: multiline(parsed.involves),
      benefits: multiline(parsed.benefits),
      alternatives: multiline(parsed.alternatives),
      recovery: multiline(parsed.recovery),
      warnings: multiline(parsed.warnings),
      options,
      risks,
      updatedAt: new Date(),
    })
    .where(eq(consentiqProcedures.id, parsed.id));

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

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

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

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

  await db
    .update(consentiqProcedures)
    .set({ status: parsed.status, updatedAt: new Date() })
    .where(eq(consentiqProcedures.id, parsed.id));

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

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

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