"use server";

import { revalidatePath } from "next/cache";
import { requireSession } from "@/lib/auth/session";
import { formsExecute } from "./db";
import { ensureFormsTables } from "./schema";
import { freeSlug } from "./queries";
import {
  APPLICATION_CATEGORIES,
  APPLICATION_FIELD_TYPES,
  APPLICATION_STATUS,
  encodeFields,
  slugFrom,
  uniqueFieldKeys,
  type PositionField,
} from "./contract";

// ──────────────────────────────────────────────────────────────────────────
// Schreibzugriffe auf die gemeinsame Formular-Datenbank.
// Ausschließlich Prepared Statements; kein ALTER, kein DROP, kein TRUNCATE.
// ──────────────────────────────────────────────────────────────────────────

export type FormsResult = { ok?: true; id?: number; error?: string; info?: string };

/**
 * Ausschreibungen und Bewerbungen hängen am selben Recht (`forms.manage`),
 * Kontaktanfragen an einem eigenen (`contact.manage`) — die drei Bereiche
 * sind getrennte Module.
 */
async function guard(
  permission: "forms.manage" | "contact.manage" = "forms.manage",
): Promise<{ ok: true } | { error: string }> {
  const session = await requireSession();
  if (!session.user.permissions?.includes(permission)) {
    return {
      error:
        permission === "contact.manage"
          ? "Keine Berechtigung, Kontaktanfragen zu bearbeiten."
          : "Keine Berechtigung, Ausschreibungen und Bewerbungen zu verwalten.",
    };
  }
  return { ok: true };
}

/** Alle drei Bereiche neu laden — sie teilen sich die Datenquelle. */
function revalidateForms(): void {
  revalidatePath("/positions");
  revalidatePath("/applications");
  revalidatePath("/contact");
}

function fail(err: unknown): FormsResult {
  const msg = err instanceof Error ? err.message : "Unbekannter Fehler";
  console.error("[forms] Schreibfehler:", msg);
  return { error: `Speichern fehlgeschlagen: ${msg}` };
}

// ── Stellen ───────────────────────────────────────────────────────────────

export type PositionInput = {
  title: string;
  category: string;
  summary: string;
  description: string;
  sortOrder: number;
  isActive: boolean;
  fields: { label: string; type: string; required: boolean; placeholder: string; options: string[] }[];
};

/** Felder säubern und Schlüssel nach dem gemeinsamen Verfahren vergeben. */
function normalizeFields(input: PositionInput["fields"]): PositionField[] {
  const valid = input
    .map((f) => ({
      label: (f.label ?? "").trim().slice(0, 140),
      type: f.type in APPLICATION_FIELD_TYPES ? f.type : "text",
      required: Boolean(f.required),
      placeholder: (f.placeholder ?? "").trim().slice(0, 140),
      options: (f.options ?? []).map((o) => o.trim()).filter(Boolean).slice(0, 40),
    }))
    .filter((f) => f.label.length > 0);

  const keys = uniqueFieldKeys(valid.map((f) => f.label));
  return valid.map((f, i) => ({
    key: keys[i],
    label: f.label,
    type: f.type,
    required: f.required,
    placeholder: f.placeholder,
    options: f.type === "select" ? f.options : [],
  }));
}

function validate(input: PositionInput): string | null {
  if (!input.title.trim()) return "Titel darf nicht leer sein.";
  if (!(input.category in APPLICATION_CATEGORIES)) return "Unbekannte Kategorie.";
  if (!input.description.trim()) return "Beschreibung darf nicht leer sein.";
  const fields = normalizeFields(input.fields);
  if (fields.length === 0) return "Mindestens ein Formularfeld ist nötig.";
  for (const f of fields) {
    if (f.type === "select" && f.options.length === 0) {
      return `Die Auswahlliste „${f.label}“ braucht mindestens eine Option.`;
    }
  }
  return null;
}

export async function createPositionAction(input: PositionInput): Promise<FormsResult> {
  const g = await guard();
  if ("error" in g) return { error: g.error };

  const problem = validate(input);
  if (problem) return { error: problem };

  try {
    const slug = await freeSlug(slugFrom(input.title));
    const res = await formsExecute(
      `INSERT INTO avaria_positions
         (slug, category, title, summary, description, fields_json, sort_order, is_active)
       VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
      [
        slug,
        input.category,
        input.title.trim().slice(0, 140),
        input.summary.trim().slice(0, 255),
        input.description.trim(),
        encodeFields(normalizeFields(input.fields)),
        Math.trunc(input.sortOrder) || 0,
        input.isActive ? 1 : 0,
      ],
    );
    revalidateForms();
    return { ok: true, id: Number(res.insertId) };
  } catch (err) {
    return fail(err);
  }
}

export async function updatePositionAction(
  id: number,
  input: PositionInput,
): Promise<FormsResult> {
  const g = await guard();
  if ("error" in g) return { error: g.error };

  const problem = validate(input);
  if (problem) return { error: problem };

  try {
    const slug = await freeSlug(slugFrom(input.title), id);
    await formsExecute(
      `UPDATE avaria_positions
          SET slug = ?, category = ?, title = ?, summary = ?, description = ?,
              fields_json = ?, sort_order = ?, is_active = ?
        WHERE id = ?`,
      [
        slug,
        input.category,
        input.title.trim().slice(0, 140),
        input.summary.trim().slice(0, 255),
        input.description.trim(),
        encodeFields(normalizeFields(input.fields)),
        Math.trunc(input.sortOrder) || 0,
        input.isActive ? 1 : 0,
        id,
      ],
    );
    revalidateForms();
    return { ok: true, id };
  } catch (err) {
    return fail(err);
  }
}

export async function setPositionActiveAction(id: number, active: boolean): Promise<FormsResult> {
  const g = await guard();
  if ("error" in g) return { error: g.error };
  try {
    await formsExecute("UPDATE avaria_positions SET is_active = ? WHERE id = ?", [
      active ? 1 : 0,
      id,
    ]);
    revalidateForms();
    return { ok: true, id };
  } catch (err) {
    return fail(err);
  }
}

/**
 * Stelle löschen. Bewerbungen bleiben erhalten und werden nur entkoppelt —
 * `position_title` und `category` stehen ohnehin in der Bewerbung.
 */
export async function deletePositionAction(id: number): Promise<FormsResult> {
  const g = await guard();
  if ("error" in g) return { error: g.error };
  try {
    await formsExecute("UPDATE avaria_applications SET position_id = NULL WHERE position_id = ?", [
      id,
    ]);
    await formsExecute("DELETE FROM avaria_positions WHERE id = ?", [id]);
    revalidateForms();
    return { ok: true };
  } catch (err) {
    return fail(err);
  }
}

// ── Bewerbungen ───────────────────────────────────────────────────────────

export async function setApplicationStatusAction(
  id: number,
  status: string,
): Promise<FormsResult> {
  const g = await guard();
  if ("error" in g) return { error: g.error };
  if (!(status in APPLICATION_STATUS)) return { error: "Unbekannter Status." };
  try {
    // Ein gesetzter Status bedeutet: gesehen.
    await formsExecute("UPDATE avaria_applications SET status = ?, is_read = 1 WHERE id = ?", [
      status,
      id,
    ]);
    revalidateForms();
    return { ok: true, id };
  } catch (err) {
    return fail(err);
  }
}

export async function setApplicationReadAction(id: number, read: boolean): Promise<FormsResult> {
  const g = await guard();
  if ("error" in g) return { error: g.error };
  try {
    await formsExecute("UPDATE avaria_applications SET is_read = ? WHERE id = ?", [
      read ? 1 : 0,
      id,
    ]);
    revalidateForms();
    return { ok: true, id };
  } catch (err) {
    return fail(err);
  }
}

export async function deleteApplicationAction(id: number): Promise<FormsResult> {
  const g = await guard();
  if ("error" in g) return { error: g.error };
  try {
    await formsExecute("DELETE FROM avaria_applications WHERE id = ?", [id]);
    revalidateForms();
    return { ok: true };
  } catch (err) {
    return fail(err);
  }
}

// ── Kontaktnachrichten ────────────────────────────────────────────────────

export async function setMessageReadAction(id: number, read: boolean): Promise<FormsResult> {
  const g = await guard("contact.manage");
  if ("error" in g) return { error: g.error };
  try {
    await formsExecute("UPDATE avaria_contact_messages SET is_read = ? WHERE id = ?", [
      read ? 1 : 0,
      id,
    ]);
    revalidateForms();
    return { ok: true, id };
  } catch (err) {
    return fail(err);
  }
}

export async function deleteMessageAction(id: number): Promise<FormsResult> {
  const g = await guard("contact.manage");
  if ("error" in g) return { error: g.error };
  try {
    await formsExecute("DELETE FROM avaria_contact_messages WHERE id = ?", [id]);
    revalidateForms();
    return { ok: true };
  } catch (err) {
    return fail(err);
  }
}

// ── Einrichtung ───────────────────────────────────────────────────────────

/**
 * Fehlende Tabellen anlegen — vorhandene bleiben unverändert.
 * Genügt eines der beiden Verwaltungsrechte: Die Tabellen gehören allen
 * drei Bereichen gemeinsam.
 */
export async function ensureTablesAction(): Promise<FormsResult> {
  const session = await requireSession();
  const perms = session.user.permissions ?? [];
  if (!perms.includes("forms.manage") && !perms.includes("contact.manage")) {
    return { error: "Keine Berechtigung, Tabellen anzulegen." };
  }
  try {
    const { created, existing } = await ensureFormsTables();
    revalidateForms();
    return {
      ok: true,
      info:
        created.length === 0
          ? "Alle Tabellen waren bereits vorhanden — nichts verändert."
          : `Angelegt: ${created.join(", ")}${existing.length ? ` · unverändert: ${existing.join(", ")}` : ""}`,
    };
  } catch (err) {
    return fail(err);
  }
}
