/**
 * Generic FrontendType renderer registry.
 * Maps frontendType strings to React components.
 */

import type { ComponentType } from 'react';
import type { NodeTypeParameter } from '../../../../api/workflowApi';
import type { ApiRequestFunction } from '../../../../api/workflowApi';

export interface FieldRendererProps {
  param: NodeTypeParameter;
  value: unknown;
  onChange: (value: unknown) => void;
  allParams?: Record<string, unknown>;
  instanceId?: string;
  request?: ApiRequestFunction;
  nodeType?: string;
}

export type FieldRendererComponent = ComponentType<FieldRendererProps>;

// ---------------------------------------------------------------------------
// Inline renderers for standard types
// ---------------------------------------------------------------------------

import React from 'react';

import { useLanguage } from '../../../../providers/language/LanguageContext';

const TextInput: React.FC<FieldRendererProps> = ({ param, value, onChange }) => (
  <div style={{ marginBottom: 8 }}>
    <label style={{ display: 'block', fontSize: 12, marginBottom: 2 }}>{param.description || param.name}</label>
    <input
      type="text"
      value={typeof value === 'string' ? value : (value != null ? String(value) : '')}
      onChange={(e) => onChange(e.target.value)}
      placeholder={param.name}
      style={{ width: '100%', padding: '4px 8px', borderRadius: 4, border: '1px solid #ccc' }}
    />
  </div>
);

const TextareaInput: React.FC<FieldRendererProps> = ({ param, value, onChange }) => (
  <div style={{ marginBottom: 8 }}>
    <label style={{ display: 'block', fontSize: 12, marginBottom: 2 }}>{param.description || param.name}</label>
    <textarea
      value={typeof value === 'string' ? value : (value != null ? String(value) : '')}
      onChange={(e) => onChange(e.target.value)}
      placeholder={param.name}
      rows={4}
      style={{ width: '100%', padding: '4px 8px', borderRadius: 4, border: '1px solid #ccc', resize: 'vertical' }}
    />
  </div>
);

const NumberInput: React.FC<FieldRendererProps> = ({ param, value, onChange }) => (
  <div style={{ marginBottom: 8 }}>
    <label style={{ display: 'block', fontSize: 12, marginBottom: 2 }}>{param.description || param.name}</label>
    <input
      type="number"
      value={typeof value === 'number' ? value : (value != null ? Number(value) || 0 : '')}
      onChange={(e) => onChange(e.target.value ? Number(e.target.value) : undefined)}
      style={{ width: '100%', padding: '4px 8px', borderRadius: 4, border: '1px solid #ccc' }}
    />
  </div>
);

const CheckboxInput: React.FC<FieldRendererProps> = ({ param, value, onChange }) => (
  <div style={{ marginBottom: 8, display: 'flex', alignItems: 'center', gap: 8 }}>
    <input
      type="checkbox"
      checked={Boolean(value)}
      onChange={(e) => onChange(e.target.checked)}
    />
    <label style={{ fontSize: 12 }}>{param.description || param.name}</label>
  </div>
);

const DateInput: React.FC<FieldRendererProps> = ({ param, value, onChange }) => (
  <div style={{ marginBottom: 8 }}>
    <label style={{ display: 'block', fontSize: 12, marginBottom: 2 }}>{param.description || param.name}</label>
    <input
      type="date"
      value={typeof value === 'string' ? value : ''}
      onChange={(e) => onChange(e.target.value)}
      style={{ width: '100%', padding: '4px 8px', borderRadius: 4, border: '1px solid #ccc' }}
    />
  </div>
);

const SelectInput: React.FC<FieldRendererProps> = ({ param, value, onChange }) => {
  const options: string[] =
    (param.frontendOptions?.options as string[]) || (param.options as string[]) || [];
  return (
    <div style={{ marginBottom: 8 }}>
      <label style={{ display: 'block', fontSize: 12, marginBottom: 2 }}>{param.description || param.name}</label>
      <select
        value={typeof value === 'string' ? value : ''}
        onChange={(e) => onChange(e.target.value)}
        style={{ width: '100%', padding: '4px 8px', borderRadius: 4, border: '1px solid #ccc' }}
      >
        <option value="">—</option>
        {options.map((opt) => (
          <option key={opt} value={opt}>{opt}</option>
        ))}
      </select>
    </div>
  );
};

const MultiSelectInput: React.FC<FieldRendererProps> = ({ param, value, onChange }) => {
  const options: string[] =
    (param.frontendOptions?.options as string[]) || (param.options as string[]) || [];
  const selected = Array.isArray(value) ? value : [];
  const toggle = (opt: string) => {
    const next = selected.includes(opt) ? selected.filter((v: string) => v !== opt) : [...selected, opt];
    onChange(next);
  };
  return (
    <div style={{ marginBottom: 8 }}>
      <label style={{ display: 'block', fontSize: 12, marginBottom: 2 }}>{param.description || param.name}</label>
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4 }}>
        {options.map((opt) => (
          <label key={opt} style={{ fontSize: 12, display: 'flex', alignItems: 'center', gap: 2 }}>
            <input type="checkbox" checked={selected.includes(opt)} onChange={() => toggle(opt)} />
            {opt}
          </label>
        ))}
      </div>
    </div>
  );
};

const JsonEditor: React.FC<FieldRendererProps> = ({ param, value, onChange }) => {
  const strVal = typeof value === 'string' ? value : JSON.stringify(value ?? '', null, 2);
  return (
    <div style={{ marginBottom: 8 }}>
      <label style={{ display: 'block', fontSize: 12, marginBottom: 2 }}>{param.description || param.name}</label>
      <textarea
        value={strVal}
        onChange={(e) => {
          try { onChange(JSON.parse(e.target.value)); } catch { onChange(e.target.value); }
        }}
        rows={6}
        style={{ width: '100%', padding: '4px 8px', borderRadius: 4, border: '1px solid #ccc', fontFamily: 'monospace', fontSize: 11, resize: 'vertical' }}
      />
    </div>
  );
};

const HiddenInput: React.FC<FieldRendererProps> = () => null;

const ConnectionPicker: React.FC<FieldRendererProps> = ({ param, value, onChange, instanceId, request }) => {
  const { t } = useLanguage();
  const [connections, setConnections] = React.useState<Array<{ id: string; label: string }>>([]);
  React.useEffect(() => {
    if (!instanceId || !request) return;
    request({ url: `/api/graphicalEditor/${instanceId}/options/user.connection`, method: 'get' })
      .then((res: unknown) => {
        const data = res as { options?: Array<{ value: string; label: string }> };
        setConnections((data?.options || []).map((o) => ({ id: o.value, label: o.label })));
      })
      .catch(() => {});
  }, [instanceId, request]);
  return (
    <div style={{ marginBottom: 8 }}>
      <label style={{ display: 'block', fontSize: 12, marginBottom: 2 }}>{param.description || param.name}</label>
      <select
        value={typeof value === 'string' ? value : ''}
        onChange={(e) => onChange(e.target.value)}
        style={{ width: '100%', padding: '4px 8px', borderRadius: 4, border: '1px solid #ccc' }}
      >
        <option value="">{t('Verbindung wählen')}</option>
        {connections.map((c) => (
          <option key={c.id} value={c.id}>{c.label}</option>
        ))}
      </select>
    </div>
  );
};

const FolderPicker: React.FC<FieldRendererProps> = ({ param, value, onChange, allParams }) => {
  const { t } = useLanguage();
  const dependsOn = param.frontendOptions?.dependsOn as string | undefined;
  const depValue = dependsOn ? allParams?.[dependsOn] : undefined;
  const disabled = dependsOn && !depValue;
  return (
    <div style={{ marginBottom: 8 }}>
      <label style={{ display: 'block', fontSize: 12, marginBottom: 2 }}>{param.description || param.name}</label>
      <input
        type="text"
        value={typeof value === 'string' ? value : ''}
        onChange={(e) => onChange(e.target.value)}
        disabled={!!disabled}
        placeholder={disabled ? t('Zuerst {field} wählen', { field: dependsOn ?? '' }) : param.name}
        style={{ width: '100%', padding: '4px 8px', borderRadius: 4, border: '1px solid #ccc', opacity: disabled ? 0.5 : 1 }}
      />
    </div>
  );
};

const CaseListEditor: React.FC<FieldRendererProps> = ({ param, value, onChange }) => {
  const { t } = useLanguage();
  const cases = Array.isArray(value) ? value : [];
  const addCase = () => onChange([...cases, { operator: 'eq', value: '' }]);
  const removeCase = (idx: number) => onChange(cases.filter((_: unknown, i: number) => i !== idx));
  const updateCase = (idx: number, field: string, val: unknown) => {
    const next = [...cases];
    next[idx] = { ...(next[idx] as Record<string, unknown>), [field]: val };
    onChange(next);
  };
  return (
    <div style={{ marginBottom: 8 }}>
      <label style={{ display: 'block', fontSize: 12, marginBottom: 2 }}>{param.description || param.name}</label>
      {cases.map((c: Record<string, unknown>, i: number) => (
        <div key={i} style={{ display: 'flex', gap: 4, marginBottom: 4 }}>
          <select value={String(c.operator || 'eq')} onChange={(e) => updateCase(i, 'operator', e.target.value)} style={{ flex: 1, padding: '2px 4px', borderRadius: 4, border: '1px solid #ccc' }}>
            <option value="eq">{t('ist gleich')}</option>
            <option value="neq">{t('ungleich')}</option>
            <option value="contains">{t('enthält')}</option>
            <option value="gt">{t('größer als')}</option>
            <option value="lt">{t('kleiner als')}</option>
          </select>
          <input type="text" value={String(c.value ?? '')} onChange={(e) => updateCase(i, 'value', e.target.value)} style={{ flex: 2, padding: '2px 4px', borderRadius: 4, border: '1px solid #ccc' }} />
          <button onClick={() => removeCase(i)} style={{ padding: '2px 8px', borderRadius: 4, border: '1px solid #ccc', cursor: 'pointer' }}>×</button>
        </div>
      ))}
      <button onClick={addCase} style={{ padding: '2px 8px', borderRadius: 4, border: '1px solid #ccc', cursor: 'pointer', fontSize: 12 }}>{t('Fall hinzufügen')}</button>
    </div>
  );
};

const FieldBuilderEditor: React.FC<FieldRendererProps> = ({ param, value, onChange }) => {
  const { t } = useLanguage();
  const fields = Array.isArray(value) ? value : [];
  const addField = () => onChange([...fields, { name: '', type: 'text', label: '', required: false }]);
  const removeField = (idx: number) => onChange(fields.filter((_: unknown, i: number) => i !== idx));
  const updateField = (idx: number, field: string, val: unknown) => {
    const next = [...fields];
    next[idx] = { ...(next[idx] as Record<string, unknown>), [field]: val };
    onChange(next);
  };
  return (
    <div style={{ marginBottom: 8 }}>
      <label style={{ display: 'block', fontSize: 12, marginBottom: 2 }}>{param.description || param.name}</label>
      {fields.map((f: Record<string, unknown>, i: number) => (
        <div key={i} style={{ display: 'flex', gap: 4, marginBottom: 4, alignItems: 'center' }}>
          <input type="text" placeholder={t('Name')} value={String(f.name ?? '')} onChange={(e) => updateField(i, 'name', e.target.value)} style={{ flex: 1, padding: '2px 4px', borderRadius: 4, border: '1px solid #ccc' }} />
          <select value={String(f.type ?? 'text')} onChange={(e) => updateField(i, 'type', e.target.value)} style={{ flex: 1, padding: '2px 4px', borderRadius: 4, border: '1px solid #ccc' }}>
            <option value="text">{t('Text')}</option>
            <option value="number">{t('Zahl')}</option>
            <option value="date">{t('Datum')}</option>
            <option value="checkbox">{t('Kontrollkästchen')}</option>
            <option value="select">{t('Auswahl')}</option>
            <option value="textarea">{t('Mehrzeilig')}</option>
          </select>
          <input type="text" placeholder={t('Bezeichnung')} value={String(f.label ?? '')} onChange={(e) => updateField(i, 'label', e.target.value)} style={{ flex: 1, padding: '2px 4px', borderRadius: 4, border: '1px solid #ccc' }} />
          <label style={{ fontSize: 11, display: 'flex', alignItems: 'center', gap: 2 }}>
            <input type="checkbox" checked={Boolean(f.required)} onChange={(e) => updateField(i, 'required', e.target.checked)} /> {t('Pflicht')}
          </label>
          <button onClick={() => removeField(i)} style={{ padding: '2px 8px', borderRadius: 4, border: '1px solid #ccc', cursor: 'pointer' }}>×</button>
        </div>
      ))}
      <button onClick={addField} style={{ padding: '2px 8px', borderRadius: 4, border: '1px solid #ccc', cursor: 'pointer', fontSize: 12 }}>{t('Feld hinzufügen')}</button>
    </div>
  );
};

const KeyValueRowsEditor: React.FC<FieldRendererProps> = ({ param, value, onChange }) => {
  const { t } = useLanguage();
  const rows = Array.isArray(value) ? value : [];
  const addRow = () => onChange([...rows, { key: '', value: '' }]);
  const removeRow = (idx: number) => onChange(rows.filter((_: unknown, i: number) => i !== idx));
  const updateRow = (idx: number, field: string, val: string) => {
    const next = [...rows];
    next[idx] = { ...(next[idx] as Record<string, unknown>), [field]: val };
    onChange(next);
  };
  return (
    <div style={{ marginBottom: 8 }}>
      <label style={{ display: 'block', fontSize: 12, marginBottom: 2 }}>{param.description || param.name}</label>
      {rows.map((r: Record<string, unknown>, i: number) => (
        <div key={i} style={{ display: 'flex', gap: 4, marginBottom: 4 }}>
          <input type="text" placeholder={t('Schlüssel')} value={String(r.key ?? r.fieldKey ?? '')} onChange={(e) => updateRow(i, 'key', e.target.value)} style={{ flex: 1, padding: '2px 4px', borderRadius: 4, border: '1px solid #ccc' }} />
          <input type="text" placeholder={t('Wert')} value={String(r.value ?? '')} onChange={(e) => updateRow(i, 'value', e.target.value)} style={{ flex: 2, padding: '2px 4px', borderRadius: 4, border: '1px solid #ccc' }} />
          <button onClick={() => removeRow(i)} style={{ padding: '2px 8px', borderRadius: 4, border: '1px solid #ccc', cursor: 'pointer' }}>×</button>
        </div>
      ))}
      <button onClick={addRow} style={{ padding: '2px 8px', borderRadius: 4, border: '1px solid #ccc', cursor: 'pointer', fontSize: 12 }}>{t('Zeile hinzufügen')}</button>
    </div>
  );
};

const CronBuilder: React.FC<FieldRendererProps> = ({ param, value, onChange }) => {
  const { t } = useLanguage();
  return (
    <div style={{ marginBottom: 8 }}>
      <label style={{ display: 'block', fontSize: 12, marginBottom: 2 }}>{param.description || param.name}</label>
      <input
        type="text"
        value={typeof value === 'string' ? value : ''}
        onChange={(e) => onChange(e.target.value)}
        placeholder={t('0 9 * * *')}
        style={{ width: '100%', padding: '4px 8px', borderRadius: 4, border: '1px solid #ccc', fontFamily: 'monospace' }}
      />
      <p style={{ fontSize: 10, color: '#888', margin: '2px 0 0' }}>{t('Cron: Min Stunde Tag Monat')}</p>
    </div>
  );
};

const ConditionBuilder: React.FC<FieldRendererProps> = ({ param, value, onChange }) => {
  const { t } = useLanguage();
  const cond = (typeof value === 'object' && value !== null) ? value as Record<string, unknown> : {};
  const update = (field: string, val: unknown) => onChange({ ...cond, type: 'condition', [field]: val });
  return (
    <div style={{ marginBottom: 8 }}>
      <label style={{ display: 'block', fontSize: 12, marginBottom: 2 }}>{param.description || param.name}</label>
      <div style={{ display: 'flex', gap: 4 }}>
        <select value={String(cond.operator ?? 'eq')} onChange={(e) => update('operator', e.target.value)} style={{ flex: 1, padding: '2px 4px', borderRadius: 4, border: '1px solid #ccc' }}>
          <option value="eq">{t('ist gleich')}</option>
          <option value="neq">{t('ungleich')}</option>
          <option value="gt">{t('größer als')}</option>
          <option value="lt">{t('kleiner als')}</option>
          <option value="contains">{t('enthält')}</option>
          <option value="empty">{t('ist leer')}</option>
          <option value="not_empty">{t('ist nicht leer')}</option>
          <option value="is_true">{t('ist wahr')}</option>
          <option value="is_false">{t('ist falsch')}</option>
        </select>
        <input type="text" placeholder={t('Wert')} value={String(cond.value ?? '')} onChange={(e) => update('value', e.target.value)} style={{ flex: 2, padding: '2px 4px', borderRadius: 4, border: '1px solid #ccc' }} />
      </div>
    </div>
  );
};

const MappingTableEditor: React.FC<FieldRendererProps> = ({ param, value, onChange }) => {
  const { t } = useLanguage();
  const mappings = Array.isArray(value) ? value : [];
  const addMapping = () => onChange([...mappings, { sourceField: '', outputField: '' }]);
  const removeMapping = (idx: number) => onChange(mappings.filter((_: unknown, i: number) => i !== idx));
  const updateMapping = (idx: number, field: string, val: string) => {
    const next = [...mappings];
    next[idx] = { ...(next[idx] as Record<string, unknown>), [field]: val };
    onChange(next);
  };
  return (
    <div style={{ marginBottom: 8 }}>
      <label style={{ display: 'block', fontSize: 12, marginBottom: 2 }}>{param.description || param.name}</label>
      {mappings.map((m: Record<string, unknown>, i: number) => (
        <div key={i} style={{ display: 'flex', gap: 4, marginBottom: 4 }}>
          <input type="text" placeholder={t('Quellfeld')} value={String(m.sourceField ?? '')} onChange={(e) => updateMapping(i, 'sourceField', e.target.value)} style={{ flex: 1, padding: '2px 4px', borderRadius: 4, border: '1px solid #ccc' }} />
          <span style={{ alignSelf: 'center' }}>→</span>
          <input type="text" placeholder={t('Ausgabefeld')} value={String(m.outputField ?? '')} onChange={(e) => updateMapping(i, 'outputField', e.target.value)} style={{ flex: 1, padding: '2px 4px', borderRadius: 4, border: '1px solid #ccc' }} />
          <button onClick={() => removeMapping(i)} style={{ padding: '2px 8px', borderRadius: 4, border: '1px solid #ccc', cursor: 'pointer' }}>×</button>
        </div>
      ))}
      <button onClick={addMapping} style={{ padding: '2px 8px', borderRadius: 4, border: '1px solid #ccc', cursor: 'pointer', fontSize: 12 }}>{t('Zuordnung hinzufügen')}</button>
    </div>
  );
};

const FilterExpressionEditor: React.FC<FieldRendererProps> = ({ param, value, onChange }) => {
  const { t } = useLanguage();
  const cond = (typeof value === 'object' && value !== null) ? value as Record<string, unknown> : {};
  const update = (field: string, val: unknown) => onChange({ ...cond, [field]: val });
  return (
    <div style={{ marginBottom: 8 }}>
      <label style={{ display: 'block', fontSize: 12, marginBottom: 2 }}>{param.description || param.name}</label>
      <div style={{ display: 'flex', gap: 4 }}>
        <input type="text" placeholder={t('Feld')} value={String(cond.field ?? '')} onChange={(e) => update('field', e.target.value)} style={{ flex: 1, padding: '2px 4px', borderRadius: 4, border: '1px solid #ccc' }} />
        <select value={String(cond.operator ?? 'eq')} onChange={(e) => update('operator', e.target.value)} style={{ flex: 1, padding: '2px 4px', borderRadius: 4, border: '1px solid #ccc' }}>
          <option value="eq">{t('ist gleich')}</option>
          <option value="neq">{t('ungleich')}</option>
          <option value="contains">{t('enthält')}</option>
          <option value="startsWith">{t('beginnt mit')}</option>
          <option value="isEmpty">{t('ist leer')}</option>
          <option value="isNotEmpty">{t('ist nicht leer')}</option>
          <option value="gt">{t('größer als')}</option>
          <option value="lt">{t('kleiner als')}</option>
        </select>
        <input type="text" placeholder={t('Wert')} value={String(cond.value ?? '')} onChange={(e) => update('value', e.target.value)} style={{ flex: 1, padding: '2px 4px', borderRadius: 4, border: '1px solid #ccc' }} />
      </div>
    </div>
  );
};

// ---------------------------------------------------------------------------
// Registry
// ---------------------------------------------------------------------------

export const FRONTEND_TYPE_RENDERERS: Record<string, FieldRendererComponent> = {
  text: TextInput,
  textarea: TextareaInput,
  number: NumberInput,
  checkbox: CheckboxInput,
  date: DateInput,
  datetime: DateInput,
  email: TextInput,
  select: SelectInput,
  multiselect: MultiSelectInput,
  json: JsonEditor,
  file: TextInput,
  hidden: HiddenInput,
  userConnection: ConnectionPicker,
  sharepointFolder: FolderPicker,
  sharepointFile: FolderPicker,
  clickupList: FolderPicker,
  clickupTask: FolderPicker,
  caseList: CaseListEditor,
  fieldBuilder: FieldBuilderEditor,
  keyValueRows: KeyValueRowsEditor,
  cron: CronBuilder,
  condition: ConditionBuilder,
  mappingTable: MappingTableEditor,
  filterExpression: FilterExpressionEditor,
};

export default FRONTEND_TYPE_RENDERERS;
