"use server";

import { and, eq, inArray } from "drizzle-orm";
import { revalidatePath } from "next/cache";
import { db } from "@/db";
import { merkmale, merkmalValues, vehicleTemplateMerkmale } from "@/db/schema";
import { requirePlatformAdmin } from "@/lib/auth/guards";
import { writeAudit } from "@/lib/audit";
import { uuidSchema } from "@/lib/validation/common";

export type ActionResult = { ok: true } | { ok: false; error: string };

/**
 * Promoviert ein vorgeschlagenes Merkmal: setzt `status = 'active'`. Der
 * partielle Unique-Index `merkmale_active_name_uq` verhindert dabei zwei aktive
 * Merkmale gleichen Namens (DB-WS). Guard zuerst. Audit `merkmal.promote`.
 */
export async function promoteMerkmal(merkmalId: unknown): Promise<ActionResult> {
  const s = await requirePlatformAdmin();
  const id = uuidSchema.safeParse(merkmalId);
  if (!id.success) return { ok: false, error: "Ungültige ID." };

  try {
    await db.transaction(async (tx) => {
      await tx
        .update(merkmale)
        .set({ status: "active" })
        .where(eq(merkmale.id, id.data));
      await writeAudit(
        s.user.id,
        "merkmal.promote",
        "merkmal",
        id.data,
        undefined,
        tx,
      );
    });
  } catch {
    return {
      ok: false,
      error:
        "Es existiert bereits ein aktives Merkmal mit diesem Namen. Bitte stattdessen zusammenführen.",
    };
  }

  revalidatePath("/admin/merkmale/proposals");
  return { ok: true };
}

/**
 * Führt ein vorgeschlagenes Merkmal in ein Ziel-Merkmal zusammen: hängt alle
 * `merkmal_values` und `vehicle_template_merkmale` auf das Ziel um und löscht
 * das vorgeschlagene Merkmal. Typ-Kompatibilität wird serverseitig erzwungen.
 * Guard zuerst. Audit `merkmal.merge`.
 */
export async function mergeMerkmal(input: {
  proposedId: unknown;
  zielId: unknown;
}): Promise<ActionResult> {
  const s = await requirePlatformAdmin();
  const proposed = uuidSchema.safeParse(input.proposedId);
  const ziel = uuidSchema.safeParse(input.zielId);
  if (!proposed.success || !ziel.success) {
    return { ok: false, error: "Ungültige ID." };
  }
  if (proposed.data === ziel.data) {
    return { ok: false, error: "Quelle und Ziel müssen verschieden sein." };
  }

  const rows = await db
    .select({ id: merkmale.id, typ: merkmale.typ, status: merkmale.status })
    .from(merkmale);
  const src = rows.find((r) => r.id === proposed.data);
  const dst = rows.find((r) => r.id === ziel.data);
  if (!src || !dst) return { ok: false, error: "Merkmal nicht gefunden." };
  if (src.typ !== dst.typ) {
    return {
      ok: false,
      error: "Nur Merkmale gleichen Typs können zusammengeführt werden.",
    };
  }

  try {
    await db.transaction(async (tx) => {
      // vehicle_template_merkmale hat den zusammengesetzten PK
      // (template_id, merkmal_id). Hat eine Vorlage bereits sowohl das
      // vorgeschlagene als auch das Ziel-Merkmal, würde ein pauschales
      // Umhängen den PK verletzen. Solche kollidierenden Proposed-Zeilen
      // werden daher gelöscht statt umgehängt.
      const proposedVtm = await tx
        .select({ templateId: vehicleTemplateMerkmale.templateId })
        .from(vehicleTemplateMerkmale)
        .where(eq(vehicleTemplateMerkmale.merkmalId, proposed.data));
      const zielVtm = await tx
        .select({ templateId: vehicleTemplateMerkmale.templateId })
        .from(vehicleTemplateMerkmale)
        .where(eq(vehicleTemplateMerkmale.merkmalId, ziel.data));
      const zielTemplateIds = new Set(zielVtm.map((r) => r.templateId));
      const collidingTemplateIds = proposedVtm
        .map((r) => r.templateId)
        .filter((id) => zielTemplateIds.has(id));

      if (collidingTemplateIds.length > 0) {
        await tx
          .delete(vehicleTemplateMerkmale)
          .where(
            and(
              eq(vehicleTemplateMerkmale.merkmalId, proposed.data),
              inArray(
                vehicleTemplateMerkmale.templateId,
                collidingTemplateIds,
              ),
            ),
          );
      }

      await tx
        .update(merkmalValues)
        .set({ merkmalId: ziel.data })
        .where(eq(merkmalValues.merkmalId, proposed.data));
      await tx
        .update(vehicleTemplateMerkmale)
        .set({ merkmalId: ziel.data })
        .where(eq(vehicleTemplateMerkmale.merkmalId, proposed.data));
      await tx.delete(merkmale).where(eq(merkmale.id, proposed.data));
      await writeAudit(
        s.user.id,
        "merkmal.merge",
        "merkmal",
        ziel.data,
        { merged: proposed.data },
        tx,
      );
    });
  } catch {
    return {
      ok: false,
      error: "Zusammenführen fehlgeschlagen. Bitte erneut versuchen.",
    };
  }

  revalidatePath("/admin/merkmale/proposals");
  return { ok: true };
}
