'use client';

import { useMemo, useRef, useState, useEffect } from 'react';
import { Upload, FileText, Plus, X, AlertTriangle, CheckCircle2 } from 'lucide-react';
import { cn } from '@/lib/utils';
import type { PickerRecipient } from './RecipientPicker';

// ─────────────────────────────────────────────────────────────────────────────
// Types
// ─────────────────────────────────────────────────────────────────────────────

type Row = Record<string, string>;

interface CsvData {
  headers: string[];
  rows: Row[];
  delimiter: string;
}

interface ColumnMapping {
  email: string;
  firstName?: string;
  lastName?: string;
  fullName?: string;
  company?: string;
}

type FilterOp = 'equals' | 'notEquals' | 'contains' | 'in' | 'notEmpty' | 'isEmpty';

interface CsvFilter {
  id: string;
  column: string;
  operator: FilterOp;
  /** Single value (für equals, notEquals, contains) */
  value: string;
  /** Multi-Werte (für 'in') */
  values: string[];
}

// ─────────────────────────────────────────────────────────────────────────────
// CSV-Parser (handles quoted fields with escaped quotes, auto-delim detect)
// ─────────────────────────────────────────────────────────────────────────────

function parseCSV(text: string): CsvData {
  // BOM-Stripping (Excel-Export)
  if (text.charCodeAt(0) === 0xfeff) text = text.slice(1);

  const firstLine = text.split('\n')[0] ?? '';
  // Auto-Detect: bevorzuge Semikolon (deutsche Excel-Konvention), dann Tab, dann Komma
  const candidates: { d: string; n: number }[] = [
    { d: ';', n: (firstLine.match(/;/g) ?? []).length },
    { d: '\t', n: (firstLine.match(/\t/g) ?? []).length },
    { d: ',', n: (firstLine.match(/,/g) ?? []).length },
  ];
  const delimiter = candidates.sort((a, b) => b.n - a.n)[0].d;

  const rows: string[][] = [];
  let row: string[] = [];
  let field = '';
  let inQuotes = false;

  for (let i = 0; i < text.length; i++) {
    const c = text[i];
    if (inQuotes) {
      if (c === '"') {
        if (text[i + 1] === '"') {
          field += '"';
          i++;
        } else {
          inQuotes = false;
        }
      } else {
        field += c;
      }
    } else {
      if (c === '"') {
        inQuotes = true;
      } else if (c === delimiter) {
        row.push(field);
        field = '';
      } else if (c === '\n') {
        row.push(field);
        rows.push(row);
        row = [];
        field = '';
      } else if (c === '\r') {
        // skip
      } else {
        field += c;
      }
    }
  }
  if (field.length > 0 || row.length > 0) {
    row.push(field);
    rows.push(row);
  }

  if (rows.length === 0) return { headers: [], rows: [], delimiter };
  const headers = rows[0].map((h) => h.trim());
  const dataRows = rows
    .slice(1)
    .filter((r) => r.some((c) => c.trim().length > 0));
  const objRows: Row[] = dataRows.map((r) => {
    const o: Row = {};
    headers.forEach((h, i) => {
      o[h] = (r[i] ?? '').trim();
    });
    return o;
  });
  return { headers, rows: objRows, delimiter };
}

// ─────────────────────────────────────────────────────────────────────────────
// Helpers
// ─────────────────────────────────────────────────────────────────────────────

function autoDetectMapping(headers: string[]): ColumnMapping {
  const find = (needles: string[]) =>
    headers.find((h) => needles.some((n) => h.toLowerCase().includes(n)));
  return {
    email: find(['email', 'e-mail', 'mail']) ?? '',
    firstName: find(['vorname', 'firstname', 'first_name', 'first name']),
    lastName: find(['nachname', 'lastname', 'last_name', 'surname', 'familienname']),
    fullName: find(['fullname', 'full_name', 'full name', 'kunde', 'name']),
    company: find(['firma', 'company', 'unternehmen', 'organization', 'organisation']),
  };
}

function uniqueValues(rows: Row[], col: string): string[] {
  const set = new Set<string>();
  for (const r of rows) {
    const v = r[col];
    if (v && v.trim()) set.add(v.trim());
  }
  return Array.from(set).sort((a, b) => a.localeCompare(b, 'de'));
}

function applyFilters(rows: Row[], filters: CsvFilter[]): Row[] {
  if (filters.length === 0) return rows;
  return rows.filter((row) =>
    filters.every((f) => {
      const v = (row[f.column] ?? '').trim();
      switch (f.operator) {
        case 'equals':
          return v.toLowerCase() === f.value.trim().toLowerCase();
        case 'notEquals':
          return v.toLowerCase() !== f.value.trim().toLowerCase();
        case 'contains':
          return v.toLowerCase().includes(f.value.trim().toLowerCase());
        case 'in':
          return f.values.length === 0 ? true : f.values.includes(v);
        case 'notEmpty':
          return v.length > 0;
        case 'isEmpty':
          return v.length === 0;
        default:
          return true;
      }
    }),
  );
}

const EMAIL_RX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

const OPERATORS: { value: FilterOp; label: string }[] = [
  { value: 'equals', label: 'gleich' },
  { value: 'notEquals', label: 'ungleich' },
  { value: 'contains', label: 'enthält' },
  { value: 'in', label: 'einer von …' },
  { value: 'notEmpty', label: 'nicht leer' },
  { value: 'isEmpty', label: 'leer' },
];

const LOW_CARDINALITY_THRESHOLD = 50; // unter dieser Schwelle → Multi-Select Dropdown

// ─────────────────────────────────────────────────────────────────────────────
// Component
// ─────────────────────────────────────────────────────────────────────────────

export interface CsvSourcePanelProps {
  /** Wird gerufen wann immer sich die gefilterte Empfängerliste ändert. */
  onRecipientsChange: (recipients: PickerRecipient[]) => void;
  /**
   * Optional: Wird mit den parsed CSV-Headers gerufen (nach Upload bzw. Reset).
   * Genutzt vom Parent (RecipientPicker) um die Headers als Placeholder-Chips anzuzeigen.
   * Beim Reset wird ein leeres Array gesendet.
   */
  onHeadersChange?: (headers: string[]) => void;
}

export function CsvSourcePanel({ onRecipientsChange, onHeadersChange }: CsvSourcePanelProps) {
  const [csvData, setCsvData] = useState<CsvData | null>(null);
  const [fileName, setFileName] = useState<string>('');
  const [parseError, setParseError] = useState<string | null>(null);

  const [mapping, setMapping] = useState<ColumnMapping>({ email: '' });
  const [filters, setFilters] = useState<CsvFilter[]>([]);
  /**
   * Pool-Type für Login-Direktlinks (Kompass-Magic-Links): gilt für ALLE Empfänger
   * dieses CSV-Uploads. Default 'private' weil das der häufigere Fall ist UND der
   * Shop-Backend-Default — eine Privatkunden-ID, die fälschlich als 'business'
   * markiert wird, würde im Shop 404 werfen, andersrum auch. Single Toggle pro
   * Upload ist die 95%-Lösung, weil CSVs typischerweise homogen sind.
   */
  const [poolType, setPoolType] = useState<'private' | 'business'>('private');

  const [dragActive, setDragActive] = useState(false);
  const fileInputRef = useRef<HTMLInputElement>(null);

  // Filter anwenden (memoized)
  const filteredRows = useMemo(() => {
    if (!csvData) return [];
    return applyFilters(csvData.rows, filters);
  }, [csvData, filters]);

  // Recipients ableiten — wenn email-Spalte gemappt ist
  const recipients = useMemo<PickerRecipient[]>(() => {
    if (!csvData || !mapping.email) return [];
    const seen = new Set<string>();
    const out: PickerRecipient[] = [];
    for (const r of filteredRows) {
      const email = r[mapping.email]?.trim().toLowerCase();
      if (!email || !EMAIL_RX.test(email) || seen.has(email)) continue;
      seen.add(email);
      out.push({
        email,
        firstName: mapping.firstName ? r[mapping.firstName] || undefined : undefined,
        lastName: mapping.lastName ? r[mapping.lastName] || undefined : undefined,
        fullName: mapping.fullName ? r[mapping.fullName] || undefined : undefined,
        company: mapping.company ? r[mapping.company] || undefined : undefined,
        source: 'csv',
        poolType,
      });
    }
    return out;
  }, [csvData, filteredRows, mapping, poolType]);

  // Sync mit Parent
  useEffect(() => {
    onRecipientsChange(recipients);
  }, [recipients, onRecipientsChange]);

  // Headers an Parent spiegeln — für PlaceholderLegend in RecipientPicker.
  // Beim Reset (csvData=null) → leeres Array senden.
  useEffect(() => {
    onHeadersChange?.(csvData?.headers ?? []);
  }, [csvData, onHeadersChange]);

  // ─── File-Handling ──────────────────────────────────────────────────────

  const handleFile = async (file: File) => {
    setParseError(null);
    setFileName(file.name);
    try {
      const text = await file.text();
      const parsed = parseCSV(text);
      if (parsed.headers.length === 0) {
        setParseError('CSV ist leer oder konnte nicht gelesen werden.');
        return;
      }
      if (parsed.rows.length === 0) {
        setParseError('CSV enthält Header aber keine Daten-Zeilen.');
        return;
      }
      setCsvData(parsed);
      setMapping(autoDetectMapping(parsed.headers));
      setFilters([]);
    } catch (e) {
      setParseError(e instanceof Error ? e.message : 'Fehler beim Lesen der Datei');
    }
  };

  const onDrop = (e: React.DragEvent) => {
    e.preventDefault();
    setDragActive(false);
    const file = e.dataTransfer.files[0];
    if (file) void handleFile(file);
  };

  const reset = () => {
    setCsvData(null);
    setFileName('');
    setParseError(null);
    setMapping({ email: '' });
    setFilters([]);
  };

  // ─── Filter-Handling ────────────────────────────────────────────────────

  const addFilter = () => {
    if (!csvData) return;
    const firstUnusedCol = csvData.headers.find(
      (h) => h !== mapping.email && !filters.some((f) => f.column === h),
    ) ?? csvData.headers[0];
    setFilters([
      ...filters,
      {
        id: `f${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
        column: firstUnusedCol,
        operator: 'equals',
        value: '',
        values: [],
      },
    ]);
  };

  const updateFilter = (id: string, patch: Partial<CsvFilter>) => {
    setFilters(filters.map((f) => (f.id === id ? { ...f, ...patch } : f)));
  };

  const removeFilter = (id: string) => {
    setFilters(filters.filter((f) => f.id !== id));
  };

  // ─── Render ─────────────────────────────────────────────────────────────

  // Step 1: Upload
  if (!csvData) {
    return (
      <div className="flex flex-1 flex-col overflow-hidden p-6">
        <label
          onDragEnter={(e) => { e.preventDefault(); setDragActive(true); }}
          onDragOver={(e) => { e.preventDefault(); setDragActive(true); }}
          onDragLeave={() => setDragActive(false)}
          onDrop={onDrop}
          className={cn(
            'flex flex-1 cursor-pointer flex-col items-center justify-center gap-3 rounded-lg border-2 border-dashed transition',
            dragActive
              ? 'border-zinc-900 bg-zinc-50 dark:border-zinc-100 dark:bg-zinc-900'
              : 'border-zinc-300 bg-zinc-50/50 hover:border-zinc-400 dark:border-zinc-700 dark:bg-zinc-900/30 dark:hover:border-zinc-600',
          )}
        >
          <input
            ref={fileInputRef}
            type="file"
            accept=".csv,text/csv"
            className="hidden"
            onChange={(e) => {
              const f = e.target.files?.[0];
              if (f) void handleFile(f);
            }}
          />
          <Upload className="h-10 w-10 text-zinc-400" />
          <div className="text-center">
            <p className="text-sm font-medium text-zinc-900 dark:text-zinc-100">
              CSV-Datei hierher ziehen oder klicken
            </p>
            <p className="mt-1 text-xs text-zinc-500">
              Auto-Erkennung Trennzeichen (<code>;</code> · <code>,</code> · Tab) · UTF-8 + BOM
            </p>
          </div>
        </label>

        {parseError && (
          <div className="mt-4 flex items-start gap-2 rounded-md border border-red-200 bg-red-50 p-3 text-xs text-red-800 dark:border-red-900/50 dark:bg-red-950/30">
            <AlertTriangle className="mt-0.5 h-4 w-4 shrink-0" />
            <span>{parseError}</span>
          </div>
        )}
      </div>
    );
  }

  // Step 2+: Mapping + Filter + Preview
  return (
    <div className="grid flex-1 grid-cols-[340px_1fr] gap-0 overflow-hidden">
      {/* ─── Filter-Panel ─────────────────────────────────────────────── */}
      <div className="space-y-4 overflow-y-auto border-r border-zinc-200 p-4 dark:border-zinc-800">
        {/* File-Info */}
        <div className="flex items-start gap-2 rounded-md border border-zinc-200 bg-zinc-50 p-2.5 text-xs dark:border-zinc-800 dark:bg-zinc-900">
          <FileText className="mt-0.5 h-4 w-4 shrink-0 text-zinc-500" />
          <div className="flex-1 overflow-hidden">
            <div className="truncate font-medium" title={fileName}>{fileName}</div>
            <div className="text-[10px] text-zinc-500">
              {csvData.rows.length.toLocaleString('de-DE')} Zeilen · {csvData.headers.length} Spalten · Trennzeichen <code>{csvData.delimiter === '\t' ? '\\t' : csvData.delimiter}</code>
            </div>
          </div>
          <button onClick={reset} className="rounded p-1 text-zinc-400 hover:bg-zinc-200 hover:text-zinc-700 dark:hover:bg-zinc-800" title="Andere Datei laden">
            <X className="h-3.5 w-3.5" />
          </button>
        </div>

        {/* Spalten-Mapping */}
        <div>
          <label className="text-[11px] font-semibold uppercase tracking-wider text-zinc-500">Spalten-Zuordnung</label>
          <div className="mt-1.5 space-y-2">
            <MappingField
              label="Email"
              required
              value={mapping.email}
              headers={csvData.headers}
              onChange={(v) => setMapping({ ...mapping, email: v })}
            />
            <MappingField
              label="Vorname"
              value={mapping.firstName ?? ''}
              headers={csvData.headers}
              onChange={(v) => setMapping({ ...mapping, firstName: v || undefined })}
            />
            <MappingField
              label="Nachname"
              value={mapping.lastName ?? ''}
              headers={csvData.headers}
              onChange={(v) => setMapping({ ...mapping, lastName: v || undefined })}
            />
            <MappingField
              label="Voller Name"
              value={mapping.fullName ?? ''}
              headers={csvData.headers}
              onChange={(v) => setMapping({ ...mapping, fullName: v || undefined })}
            />
            <MappingField
              label="Firma"
              value={mapping.company ?? ''}
              headers={csvData.headers}
              onChange={(v) => setMapping({ ...mapping, company: v || undefined })}
            />
          </div>
        </div>

        {/* Pool-Type für Login-Direktlinks (Kompass-Magic-Links).
            Gilt für ALLE Empfänger des Uploads — siehe poolType-State-Doc oben. */}
        <div>
          <label className="text-[11px] font-semibold uppercase tracking-wider text-zinc-500">
            Kontakt-Typ
          </label>
          <p className="mt-1 text-[10px] text-zinc-400">
            Bestimmt das Pool-Routing für <code>{'{{LOGIN_LINK}}'}</code>.
            Falsche Wahl &rarr; 404 beim Klick.
          </p>
          <div className="mt-1.5 grid grid-cols-2 gap-1 rounded-md border border-zinc-200 bg-zinc-50 p-0.5 dark:border-zinc-800 dark:bg-zinc-900">
            <button
              type="button"
              onClick={() => setPoolType('private')}
              className={cn(
                'rounded px-2 py-1.5 text-[11px] font-medium transition',
                poolType === 'private'
                  ? 'bg-white text-zinc-900 shadow-sm dark:bg-zinc-800 dark:text-zinc-100'
                  : 'text-zinc-500 hover:text-zinc-700 dark:hover:text-zinc-300',
              )}
            >
              Privatkunden
            </button>
            <button
              type="button"
              onClick={() => setPoolType('business')}
              className={cn(
                'rounded px-2 py-1.5 text-[11px] font-medium transition',
                poolType === 'business'
                  ? 'bg-white text-zinc-900 shadow-sm dark:bg-zinc-800 dark:text-zinc-100'
                  : 'text-zinc-500 hover:text-zinc-700 dark:hover:text-zinc-300',
              )}
            >
              Geschäftskunden
            </button>
          </div>
        </div>

        {/* Filter */}
        <div>
          <div className="flex items-center justify-between">
            <label className="text-[11px] font-semibold uppercase tracking-wider text-zinc-500">
              Filter ({filters.length})
            </label>
            <button
              onClick={addFilter}
              className="inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-[11px] text-zinc-600 hover:bg-zinc-100 dark:text-zinc-300 dark:hover:bg-zinc-800"
            >
              <Plus className="h-3 w-3" /> hinzufügen
            </button>
          </div>
          <div className="mt-2 space-y-2">
            {filters.length === 0 && (
              <p className="text-[11px] text-zinc-400">
                Keine Filter aktiv — alle {csvData.rows.length.toLocaleString('de-DE')} Zeilen werden übernommen.
              </p>
            )}
            {filters.map((filter) => (
              <FilterRow
                key={filter.id}
                filter={filter}
                csvData={csvData}
                onChange={(patch) => updateFilter(filter.id, patch)}
                onRemove={() => removeFilter(filter.id)}
              />
            ))}
          </div>
        </div>
      </div>

      {/* ─── Result-Panel ─────────────────────────────────────────────── */}
      <div className="flex flex-col overflow-hidden">
        {!mapping.email && (
          <div className="m-4 flex items-start gap-2 rounded-md border border-amber-200 bg-amber-50 p-3 text-xs text-amber-800 dark:border-amber-900/50 dark:bg-amber-950/30">
            <AlertTriangle className="mt-0.5 h-4 w-4 shrink-0" />
            <span>Bitte ordne eine <strong>Email-Spalte</strong> zu, damit der Versand möglich ist.</span>
          </div>
        )}

        <div className="flex items-center justify-between border-b border-zinc-200 px-4 py-2 text-xs dark:border-zinc-800">
          <span className="text-zinc-600 dark:text-zinc-400">
            <strong>{recipients.length.toLocaleString('de-DE')}</strong> gültige Empfänger
            <span className="ml-1 text-zinc-400">
              (von {filteredRows.length.toLocaleString('de-DE')} gefiltert · {csvData.rows.length.toLocaleString('de-DE')} gesamt)
            </span>
          </span>
          {recipients.length > 0 && (
            <span className="inline-flex items-center gap-1 rounded-full bg-emerald-100 px-2 py-0.5 text-[10px] text-emerald-800 dark:bg-emerald-950/50 dark:text-emerald-400">
              <CheckCircle2 className="h-3 w-3" /> bereit
            </span>
          )}
        </div>

        <div className="flex-1 overflow-auto">
          <table className="w-full text-xs">
            <thead className="sticky top-0 bg-zinc-50 dark:bg-zinc-900">
              <tr className="text-left text-[10px] uppercase tracking-wider text-zinc-500">
                {csvData.headers.map((h) => (
                  <th
                    key={h}
                    className={cn(
                      'whitespace-nowrap px-3 py-2',
                      h === mapping.email && 'bg-emerald-50 text-emerald-800 dark:bg-emerald-950/30 dark:text-emerald-400',
                    )}
                  >
                    {h}
                    {h === mapping.email && <span className="ml-1 text-[9px]">★ Email</span>}
                  </th>
                ))}
              </tr>
            </thead>
            <tbody>
              {filteredRows.slice(0, 100).map((row, i) => (
                <tr key={i} className="border-b border-zinc-100 hover:bg-zinc-50 dark:border-zinc-900 dark:hover:bg-zinc-900/50">
                  {csvData.headers.map((h) => (
                    <td
                      key={h}
                      className={cn(
                        'whitespace-nowrap px-3 py-1.5 text-[11px]',
                        h === mapping.email && 'font-mono',
                      )}
                    >
                      {row[h] || <span className="text-zinc-300">—</span>}
                    </td>
                  ))}
                </tr>
              ))}
            </tbody>
          </table>
          {filteredRows.length > 100 && (
            <div className="border-t border-zinc-200 bg-zinc-50 px-4 py-2 text-center text-[11px] text-zinc-500 dark:border-zinc-800 dark:bg-zinc-900">
              … und {(filteredRows.length - 100).toLocaleString('de-DE')} weitere Zeilen (Vorschau begrenzt auf 100)
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// Sub-Components
// ─────────────────────────────────────────────────────────────────────────────

function MappingField({
  label,
  value,
  headers,
  onChange,
  required = false,
}: {
  label: string;
  value: string;
  headers: string[];
  onChange: (v: string) => void;
  required?: boolean;
}) {
  return (
    <div className="grid grid-cols-[80px_1fr] items-center gap-2">
      <label className="text-[11px] text-zinc-600 dark:text-zinc-400">
        {label} {required && <span className="text-red-500">*</span>}
      </label>
      <select
        value={value}
        onChange={(e) => onChange(e.target.value)}
        className={cn(
          'rounded-md border bg-white px-2 py-1 text-[11px] dark:bg-zinc-900',
          required && !value
            ? 'border-red-300 dark:border-red-900'
            : 'border-zinc-200 dark:border-zinc-700',
        )}
      >
        <option value="">— nicht zugeordnet —</option>
        {headers.map((h) => (
          <option key={h} value={h}>{h}</option>
        ))}
      </select>
    </div>
  );
}

function FilterRow({
  filter,
  csvData,
  onChange,
  onRemove,
}: {
  filter: CsvFilter;
  csvData: CsvData;
  onChange: (patch: Partial<CsvFilter>) => void;
  onRemove: () => void;
}) {
  const colValues = useMemo(
    () => uniqueValues(csvData.rows, filter.column),
    [csvData.rows, filter.column],
  );
  const isLowCardinality = colValues.length > 0 && colValues.length <= LOW_CARDINALITY_THRESHOLD;
  const needsValue = filter.operator !== 'notEmpty' && filter.operator !== 'isEmpty';
  const isMulti = filter.operator === 'in';

  return (
    <div className="space-y-1.5 rounded-md border border-zinc-200 bg-white p-2 dark:border-zinc-800 dark:bg-zinc-900">
      <div className="flex items-center gap-1">
        <select
          value={filter.column}
          onChange={(e) => onChange({ column: e.target.value, value: '', values: [] })}
          className="flex-1 rounded border border-zinc-200 bg-white px-1.5 py-0.5 text-[11px] dark:border-zinc-700 dark:bg-zinc-800"
        >
          {csvData.headers.map((h) => (
            <option key={h} value={h}>{h}</option>
          ))}
        </select>
        <button
          onClick={onRemove}
          className="rounded p-1 text-zinc-400 hover:bg-zinc-100 hover:text-red-600 dark:hover:bg-zinc-800"
          title="Filter entfernen"
        >
          <X className="h-3 w-3" />
        </button>
      </div>

      <select
        value={filter.operator}
        onChange={(e) => onChange({ operator: e.target.value as FilterOp, value: '', values: [] })}
        className="w-full rounded border border-zinc-200 bg-white px-1.5 py-0.5 text-[11px] dark:border-zinc-700 dark:bg-zinc-800"
      >
        {OPERATORS.map((op) => (
          <option key={op.value} value={op.value}>{op.label}</option>
        ))}
      </select>

      {needsValue && (
        <>
          {isMulti && isLowCardinality ? (
            <MultiSelectValue
              options={colValues}
              selected={filter.values}
              onChange={(values) => onChange({ values })}
            />
          ) : isLowCardinality && !isMulti ? (
            <select
              value={filter.value}
              onChange={(e) => onChange({ value: e.target.value })}
              className="w-full rounded border border-zinc-200 bg-white px-1.5 py-0.5 text-[11px] dark:border-zinc-700 dark:bg-zinc-800"
            >
              <option value="">— Wert wählen —</option>
              {colValues.map((v) => (
                <option key={v} value={v}>{v}</option>
              ))}
            </select>
          ) : (
            <input
              type="text"
              value={filter.value}
              onChange={(e) => onChange({ value: e.target.value })}
              placeholder={isMulti ? 'Komma-getrennt' : 'Wert …'}
              onBlur={isMulti
                ? () => onChange({ values: filter.value.split(',').map((s) => s.trim()).filter(Boolean) })
                : undefined}
              className="w-full rounded border border-zinc-200 bg-white px-1.5 py-0.5 text-[11px] dark:border-zinc-700 dark:bg-zinc-800"
            />
          )}
        </>
      )}

      {colValues.length > 0 && (
        <p className="text-[10px] text-zinc-400">
          {colValues.length} eindeutige Werte
          {!isLowCardinality && ' (zu viele für Dropdown)'}
        </p>
      )}
    </div>
  );
}

function MultiSelectValue({
  options,
  selected,
  onChange,
}: {
  options: string[];
  selected: string[];
  onChange: (next: string[]) => void;
}) {
  const toggle = (v: string) => {
    if (selected.includes(v)) onChange(selected.filter((s) => s !== v));
    else onChange([...selected, v]);
  };
  return (
    <div className="max-h-32 space-y-0.5 overflow-y-auto rounded border border-zinc-200 bg-white p-1 dark:border-zinc-700 dark:bg-zinc-800">
      {options.map((v) => (
        <label
          key={v}
          className="flex cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[11px] hover:bg-zinc-100 dark:hover:bg-zinc-700"
        >
          <input
            type="checkbox"
            checked={selected.includes(v)}
            onChange={() => toggle(v)}
            className="h-3 w-3"
          />
          <span className="truncate">{v}</span>
        </label>
      ))}
    </div>
  );
}
