// ──────────────────────────────────────────────────────────────────────────
// Datenvertrag der gemeinsamen Formular-Tabellen.
//
// Diese Werte und Regeln teilen sich Team OS und die öffentliche Website.
// Änderungen hier versteht die andere Seite NICHT — nur nach Absprache.
// Bewusst ohne "server-only": Der Feld-Baukasten im Browser nutzt dieselben
// Regeln, damit Vorschau und Speicherung nicht auseinanderlaufen.
// ──────────────────────────────────────────────────────────────────────────

export const APPLICATION_CATEGORIES: Record<string, string> = {
  creator: "Creator",
  team: "Team",
};

export const APPLICATION_FIELD_TYPES: Record<string, string> = {
  text: "Einzeiliges Textfeld",
  textarea: "Mehrzeiliges Textfeld",
  email: "E-Mail-Adresse",
  url: "Link",
  number: "Zahl",
  select: "Auswahlliste",
  checkbox: "Ja/Nein-Haken",
};

export const APPLICATION_STATUS: Record<string, string> = {
  new: "Neu",
  review: "In Prüfung",
  accepted: "Angenommen",
  rejected: "Abgelehnt",
};

export const STATUS_COLOR: Record<string, string> = {
  new: "#9ed7ff",
  review: "#ffc36b",
  accepted: "#7ee787",
  rejected: "#ff7a9c",
};

export type FieldType = keyof typeof APPLICATION_FIELD_TYPES;

export type PositionField = {
  key: string;
  label: string;
  type: string;
  required: boolean;
  placeholder: string;
  options: string[];
};

// ── Umschrift ─────────────────────────────────────────────────────────────
// Umlaute VOR dem Ersetzen umschreiben — sonst entsteht aus „hauptsächlich"
// ein „haupts_chlich" statt „hauptsaechlich".
const TRANSLIT: Record<string, string> = {
  ä: "ae", ö: "oe", ü: "ue", ß: "ss",
  á: "a", à: "a", â: "a", ã: "a", å: "a",
  é: "e", è: "e", ê: "e", ë: "e",
  í: "i", ì: "i", î: "i", ï: "i",
  ó: "o", ò: "o", ô: "o", õ: "o",
  ú: "u", ù: "u", û: "u",
  ç: "c", ñ: "n", ý: "y",
};

function translit(input: string): string {
  return input
    .toLowerCase()
    .split("")
    .map((c) => TRANSLIT[c] ?? c)
    .join("");
}

/** Feldschlüssel aus einer Beschriftung (max. 40 Zeichen). */
export function fieldKeyFrom(label: string): string {
  const key = translit(label)
    .replace(/[^a-z0-9]+/g, "_")
    .replace(/^_+|_+$/g, "")
    .slice(0, 40)
    .replace(/_+$/g, "");
  return key || "feld";
}

/** Schlüssel innerhalb einer Stelle eindeutig machen: _2, _3 … */
export function uniqueFieldKeys(labels: string[]): string[] {
  const used = new Set<string>();
  return labels.map((label) => {
    const base = fieldKeyFrom(label);
    let key = base;
    let n = 2;
    while (used.has(key)) {
      key = `${base}_${n++}`.slice(0, 40);
    }
    used.add(key);
    return key;
  });
}

/** Slug aus dem Titel (max. 70 Zeichen) — steht in der öffentlichen URL. */
export function slugFrom(title: string): string {
  const slug = translit(title)
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/^-+|-+$/g, "")
    .slice(0, 70)
    .replace(/-+$/g, "");
  return slug || "stelle";
}

// ── JSON ──────────────────────────────────────────────────────────────────

/**
 * Felddefinitionen defensiv lesen: Einträge ohne `label` überspringen,
 * unbekannte Typen auf `text` zurückfallen lassen. Die andere Website
 * könnte eine neuere Fassung schreiben.
 */
export function parseFields(raw: string | null | undefined): PositionField[] {
  if (!raw) return [];
  let data: unknown;
  try {
    data = JSON.parse(raw);
  } catch {
    return [];
  }
  if (!Array.isArray(data)) return [];

  const out: PositionField[] = [];
  for (const item of data) {
    if (!item || typeof item !== "object") continue;
    const f = item as Record<string, unknown>;
    const label = typeof f.label === "string" ? f.label.trim() : "";
    if (!label) continue;

    const type = typeof f.type === "string" && f.type in APPLICATION_FIELD_TYPES ? f.type : "text";
    const key = typeof f.key === "string" && f.key ? f.key : fieldKeyFrom(label);
    const options =
      type === "select" && Array.isArray(f.options)
        ? f.options.filter((o): o is string => typeof o === "string")
        : [];

    out.push({
      key,
      label,
      type,
      required: Boolean(f.required),
      placeholder: typeof f.placeholder === "string" ? f.placeholder : "",
      options,
    });
  }
  return out;
}

/** Antworten einer Bewerbung. Die Beschriftung kommt AUS dem JSON. */
export type Answer = { key: string; label: string; value: string };

export function parseAnswers(raw: string | null | undefined): Answer[] {
  if (!raw) return [];
  let data: unknown;
  try {
    data = JSON.parse(raw);
  } catch {
    return [];
  }
  if (!data || typeof data !== "object" || Array.isArray(data)) return [];

  const out: Answer[] = [];
  for (const [key, entry] of Object.entries(data as Record<string, unknown>)) {
    if (!entry || typeof entry !== "object") {
      // Ältere oder fremde Schreibweise: nackter Wert ohne Beschriftung.
      out.push({ key, label: key, value: String(entry ?? "") });
      continue;
    }
    const e = entry as Record<string, unknown>;
    out.push({
      key,
      label: typeof e.label === "string" && e.label ? e.label : key,
      value: e.value === null || e.value === undefined ? "" : String(e.value),
    });
  }
  return out;
}

/**
 * Kodierung wie auf der PHP-Seite: JSON_UNESCAPED_UNICODE |
 * JSON_UNESCAPED_SLASHES. `JSON.stringify` maskiert Unicode ohnehin nicht;
 * Schrägstriche maskiert es ebenfalls nicht — die Ausgabe ist also gleich.
 */
export function encodeJson(value: unknown): string {
  return JSON.stringify(value);
}

/** Felddefinitionen in die Form bringen, die beide Seiten erwarten. */
export function encodeFields(fields: PositionField[]): string {
  return encodeJson(
    fields.map((f) => ({
      key: f.key,
      label: f.label,
      type: f.type,
      required: f.required,
      placeholder: f.placeholder,
      options: f.type === "select" ? f.options : [],
    })),
  );
}
