"use server";

import { and, eq } from "drizzle-orm";
import { revalidatePath } from "next/cache";
import { notFound } from "next/navigation";
import { db } from "@/db";
import { vehicles } from "@/db/schema";
import { requireWehrAdmin } from "@/lib/auth/guards";
import { writeAudit } from "@/lib/audit";
import {
  vehicleCreateSchema,
  vehicleUpdateSchema,
  vehicleStatusSchema,
  vehicleIdSchema,
  buildMerkmalValuesSchema,
} from "@/lib/validation/vehicle";
import {
  getMerkmaleForTemplate,
} from "@/server/data/merkmale";
import { getVehicleForBrigade } from "@/server/data/vehicles";
import { upsertMerkmalValues } from "@/server/merkmale/upsertValues";
import type { MerkmalDefinition } from "@/lib/merkmale/types";

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

/**
 * Löst die für ein Fahrzeug erlaubten Merkmal-Definitionen serverseitig auf
 * (NUR aus der Vorlage; ohne Vorlage keine Merkmale). Damit kann der Client
 * keine fremden Merkmale schmuggeln — die Validierung baut ihr Schema NUR aus
 * diesen Definitionen.
 */
async function vehicleMerkmalDefs(
  templateId: string | undefined,
): Promise<MerkmalDefinition[]> {
  if (!templateId) return [];
  return getMerkmaleForTemplate(templateId);
}

/**
 * Liefert die Merkmal-Definitionen einer Vorlage (für die Vorbefüllung des
 * Editors im Anlage-Formular). Guard zuerst (default-deny), auch für Lesen.
 */
export async function getTemplateMerkmaleAction(
  templateId: string,
): Promise<MerkmalDefinition[]> {
  await requireWehrAdmin();
  if (!templateId) return [];
  return getMerkmaleForTemplate(templateId);
}

/** Legt ein Fahrzeug der EIGENEN Wehr an (Guard zuerst, Audit vehicle.create). */
export async function createVehicle(
  input: unknown,
  rawWerte: unknown,
): Promise<ActionResult> {
  const s = await requireWehrAdmin();
  const parsed = vehicleCreateSchema.safeParse(input);
  if (!parsed.success) {
    return { ok: false, error: parsed.error.issues[0]?.message ?? "Ungültige Eingabe." };
  }
  const d = parsed.data;
  const defs = await vehicleMerkmalDefs(d.templateId);
  const werteParsed = buildMerkmalValuesSchema(defs).safeParse(rawWerte ?? []);
  if (!werteParsed.success) {
    return { ok: false, error: werteParsed.error.issues[0]?.message ?? "Ungültige Merkmal-Werte." };
  }

  const id = await db.transaction(async (tx) => {
    const [v] = await tx
      .insert(vehicles)
      .values({
        brigadeId: s.user.brigadeId,
        templateId: d.templateId ?? null,
        name: d.name,
        funkrufname: d.funkrufname ?? null,
        notiz: d.notiz ?? null,
      })
      .returning({ id: vehicles.id });
    if (!v) throw new Error("Fahrzeug konnte nicht angelegt werden.");
    await upsertMerkmalValues(tx, "vehicle", v.id, werteParsed.data);
    await writeAudit(
      s.user.id,
      "vehicle.create",
      "vehicle",
      v.id,
      { templateId: d.templateId ?? null },
      tx,
    );
    return v.id;
  });

  revalidatePath("/verwaltung/fahrzeuge");
  return { ok: true, id };
}

/** Bearbeitet ein Fahrzeug, NUR wenn es der eigenen Wehr gehört. */
export async function updateVehicle(
  input: unknown,
  rawWerte: unknown,
): Promise<ActionResult> {
  const s = await requireWehrAdmin();
  const parsed = vehicleUpdateSchema.safeParse(input);
  if (!parsed.success) {
    return { ok: false, error: parsed.error.issues[0]?.message ?? "Ungültige Eingabe." };
  }
  const d = parsed.data;
  const existing = await getVehicleForBrigade(d.id, s.user.brigadeId);
  if (!existing) return { ok: false, error: "Fahrzeug nicht gefunden." };

  // Vorlage ist nach Anlage fix: erlaubte Merkmale aus der GESPEICHERTEN Vorlage.
  const defs = await vehicleMerkmalDefs(existing.templateId ?? undefined);
  const werteParsed = buildMerkmalValuesSchema(defs).safeParse(rawWerte ?? []);
  if (!werteParsed.success) {
    return { ok: false, error: werteParsed.error.issues[0]?.message ?? "Ungültige Merkmal-Werte." };
  }

  await db.transaction(async (tx) => {
    await tx
      .update(vehicles)
      .set({
        name: d.name,
        funkrufname: d.funkrufname ?? null,
        notiz: d.notiz ?? null,
      })
      .where(and(eq(vehicles.id, d.id), eq(vehicles.brigadeId, s.user.brigadeId)));
    await upsertMerkmalValues(tx, "vehicle", d.id, werteParsed.data);
    await writeAudit(s.user.id, "vehicle.update", "vehicle", d.id, undefined, tx);
  });

  revalidatePath("/verwaltung/fahrzeuge");
  revalidatePath(`/verwaltung/fahrzeuge/${d.id}`);
  return { ok: true, id: d.id };
}

/** Setzt den Status eines eigenen Fahrzeugs (Audit vehicle.status). */
export async function setVehicleStatus(input: unknown): Promise<ActionResult> {
  const s = await requireWehrAdmin();
  const parsed = vehicleStatusSchema.safeParse(input);
  if (!parsed.success) return { ok: false, error: "Ungültige Eingabe." };
  const existing = await getVehicleForBrigade(parsed.data.id, s.user.brigadeId);
  if (!existing) return { ok: false, error: "Fahrzeug nicht gefunden." };

  await db.transaction(async (tx) => {
    await tx
      .update(vehicles)
      .set({ status: parsed.data.status })
      .where(
        and(
          eq(vehicles.id, parsed.data.id),
          eq(vehicles.brigadeId, s.user.brigadeId),
        ),
      );
    await writeAudit(
      s.user.id,
      "vehicle.status",
      "vehicle",
      parsed.data.id,
      { status: parsed.data.status },
      tx,
    );
  });
  revalidatePath("/verwaltung/fahrzeuge");
  return { ok: true, id: parsed.data.id };
}

/** Löscht ein eigenes Fahrzeug (Audit vehicle.delete). */
export async function deleteVehicle(input: unknown): Promise<ActionResult> {
  const s = await requireWehrAdmin();
  const parsed = vehicleIdSchema.safeParse(input);
  if (!parsed.success) return { ok: false, error: "Ungültige ID." };
  const existing = await getVehicleForBrigade(parsed.data.id, s.user.brigadeId);
  if (!existing) {
    notFound();
  }

  await db.transaction(async (tx) => {
    await tx
      .delete(vehicles)
      .where(
        and(
          eq(vehicles.id, parsed.data.id),
          eq(vehicles.brigadeId, s.user.brigadeId),
        ),
      );
    await writeAudit(s.user.id, "vehicle.delete", "vehicle", parsed.data.id, undefined, tx);
  });
  revalidatePath("/verwaltung/fahrzeuge");
  return { ok: true, id: parsed.data.id };
}
