import { and, asc, eq } from "drizzle-orm";
import { db } from "@/db";
import {
  merkmale,
  merkmalOptionen,
  merkmalValues,
  vehicleTemplateMerkmale,
  equipmentCategoryMerkmale,
} from "@/db/schema";
import type {
  MerkmalDefinition,
  MerkmalOption,
  MerkmalValueInput,
} from "@/lib/merkmale/types";

/**
 * Lesehelfer für Merkmal-Definitionen (Workstream 7). Lösen die Vorgabewerte aus
 * den DREI typisierten Spalten (`vorgabewert_num/_text/_bool`) und laden je
 * enum-Merkmal die Optionen. Genutzt von Fahrzeug-/Geräteformularen, um den
 * typisierten Editor vorzubefüllen.
 */

async function optionenFor(
  merkmalIds: string[],
): Promise<Map<string, MerkmalOption[]>> {
  const map = new Map<string, MerkmalOption[]>();
  if (merkmalIds.length === 0) return map;
  const rows = await db
    .select({
      merkmalId: merkmalOptionen.merkmalId,
      wert: merkmalOptionen.wert,
      label: merkmalOptionen.label,
      reihenfolge: merkmalOptionen.reihenfolge,
    })
    .from(merkmalOptionen)
    .orderBy(asc(merkmalOptionen.reihenfolge), asc(merkmalOptionen.label));
  for (const r of rows) {
    if (!merkmalIds.includes(r.merkmalId)) continue;
    const list = map.get(r.merkmalId) ?? [];
    list.push({ wert: r.wert, label: r.label });
    map.set(r.merkmalId, list);
  }
  return map;
}

/**
 * Liefert die Pflicht-/Vorgabemerkmale einer Fahrzeug-Vorlage, geordnet.
 * Vorgabewerte werden typgerecht aus drei Spalten gelesen.
 */
export async function getMerkmaleForTemplate(
  templateId: string,
): Promise<MerkmalDefinition[]> {
  const rows = await db
    .select({
      merkmalId: merkmale.id,
      name: merkmale.name,
      typ: merkmale.typ,
      einheit: merkmale.einheit,
      pflicht: vehicleTemplateMerkmale.pflicht,
      reihenfolge: vehicleTemplateMerkmale.reihenfolge,
      vorgabeNum: vehicleTemplateMerkmale.vorgabewertNum,
      vorgabeText: vehicleTemplateMerkmale.vorgabewertText,
      vorgabeBool: vehicleTemplateMerkmale.vorgabewertBool,
    })
    .from(vehicleTemplateMerkmale)
    .innerJoin(merkmale, eq(merkmale.id, vehicleTemplateMerkmale.merkmalId))
    .where(eq(vehicleTemplateMerkmale.templateId, templateId))
    .orderBy(asc(vehicleTemplateMerkmale.reihenfolge), asc(merkmale.name));

  const opts = await optionenFor(rows.map((r) => r.merkmalId));
  return rows.map((r) => ({
    merkmalId: r.merkmalId,
    name: r.name,
    typ: r.typ,
    einheit: r.einheit,
    pflicht: r.pflicht,
    reihenfolge: r.reihenfolge,
    optionen: opts.get(r.merkmalId) ?? [],
    vorgabeNum: r.vorgabeNum,
    vorgabeText: r.vorgabeText,
    vorgabeBool: r.vorgabeBool,
  }));
}

/**
 * Liefert die Merkmale einer Geräte-Kategorie, geordnet. Kategorien tragen
 * keine Vorgabewerte/Pflicht — beide bleiben neutral (`pflicht=false`).
 */
export async function getMerkmaleForCategory(
  categoryId: string,
): Promise<MerkmalDefinition[]> {
  const rows = await db
    .select({
      merkmalId: merkmale.id,
      name: merkmale.name,
      typ: merkmale.typ,
      einheit: merkmale.einheit,
      reihenfolge: equipmentCategoryMerkmale.reihenfolge,
    })
    .from(equipmentCategoryMerkmale)
    .innerJoin(merkmale, eq(merkmale.id, equipmentCategoryMerkmale.merkmalId))
    .where(eq(equipmentCategoryMerkmale.categoryId, categoryId))
    .orderBy(asc(equipmentCategoryMerkmale.reihenfolge), asc(merkmale.name));

  const opts = await optionenFor(rows.map((r) => r.merkmalId));
  return rows.map((r) => ({
    merkmalId: r.merkmalId,
    name: r.name,
    typ: r.typ,
    einheit: r.einheit,
    pflicht: false,
    reihenfolge: r.reihenfolge,
    optionen: opts.get(r.merkmalId) ?? [],
    vorgabeNum: null,
    vorgabeText: null,
    vorgabeBool: null,
  }));
}

/**
 * Liest die aktuell gespeicherten Merkmal-Werte einer Entity (für die
 * Bearbeiten-Ansicht). Liefert `MerkmalValueInput[]` (genau eine Wertspalte je
 * Eintrag gesetzt).
 */
export async function getMerkmalValuesForEntity(
  entityTyp: "vehicle" | "equipment",
  entityId: string,
): Promise<MerkmalValueInput[]> {
  const rows = await db
    .select({
      merkmalId: merkmalValues.merkmalId,
      num: merkmalValues.valueNum,
      text: merkmalValues.valueText,
      bool: merkmalValues.valueBool,
    })
    .from(merkmalValues)
    .where(
      and(
        eq(merkmalValues.entityTyp, entityTyp),
        eq(merkmalValues.entityId, entityId),
      ),
    );
  return rows.map((r) => ({
    merkmalId: r.merkmalId,
    num: r.num,
    text: r.text,
    bool: r.bool,
  }));
}
