/**
 * GraphicalEditorWorkflowsTasksPage
 * Tasks only (no workflow grouping).
 * Open tasks at top, completed tasks at bottom (expandable, scrollable).
 * Each task shows workflow, created, due, step, type, and action.
 * Right column: active workflows with manual or form entry point — start via execute (same as Workflows page).
 */
import React, { useState, useEffect, useCallback, useRef } from 'react';
import { Link } from 'react-router-dom';
import { FaChevronDown, FaChevronRight, FaPlay, FaSpinner, FaTimes, FaUpload } from 'react-icons/fa';
import { useInstanceId } from '../../../hooks/useCurrentInstance';
import { useApiRequest } from '../../../hooks/useApi';
import {
  fetchTasks,
  cancelPendingTaskStopRun,
  completeTask,
  fetchCompletedRuns,
  fetchWorkflows,
  executeGraph,
  loadClickupListTasksForDropdown,
  type Automation2Task,
  type Automation2Workflow,
  type CompletedRun,
  type ApiRequestFunction,
} from '../../../api/workflowApi';
import { useToast } from '../../../contexts/ToastContext';
import { Popup } from '../../../components/UiComponents/Popup';
import { getAcceptStringFromConfig, fileMatchesAccept } from '../../../components/FlowEditor';
import { useFileOperations } from '../../../hooks/useFiles';
import styles from './Automation2WorkflowsTasks.module.css';
import { normalizeFormFieldOptions } from '../../../components/FlowEditor/nodes/form';

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

function _nodeTypeLabel(nodeType: string, t: (k: string) => string): string {
  switch (nodeType) {
    case 'input.form': return t('Formular');
    case 'input.approval': return t('Genehmigung');
    case 'input.upload': return t('Upload');
    case 'input.comment': return t('Kommentar');
    case 'input.review': return t('Prüfung');
    case 'input.selection': return t('Auswahl');
    case 'input.confirmation': return t('Bestätigung');
    default: return nodeType;
  }
}

function formatTimestamp(ts?: number): string {
  if (ts == null || ts <= 0) return '—';
  const d = new Date(typeof ts === 'number' && ts < 1e12 ? ts * 1000 : ts);
  return d.toLocaleString('de-DE', {
    day: '2-digit',
    month: '2-digit',
    year: 'numeric',
    hour: '2-digit',
    minute: '2-digit',
  });
}

function getNodeStepLabel(config: Record<string, unknown>): string {
  const title = config?.title;
  if (typeof title === 'string' && title.trim()) return title;
  const label = config?.label;
  if (typeof label === 'string' && label.trim()) return label;
  if (typeof label === 'object' && label != null && 'de' in (label as Record<string, string>)) {
    return (label as Record<string, string>).de ?? (label as Record<string, string>).en ?? '';
  }
  return '';
}

/** Active workflow with at least one enabled manual or form start (same idea as Tasks / editor on-demand). */
function hasManualOrFormInvocation(wf: Automation2Workflow): boolean {
  const invs = wf.invocations || [];
  return invs.some(
    (i) => i.enabled !== false && (i.kind === 'manual' || i.kind === 'form')
  );
}

/**
 * Primary entry for execute — POST /api/workflows/{instanceId}/execute with collected inputs.
 * (manual first, then form or api).
 */
function getPrimaryEntryPoint(wf: Automation2Workflow) {
  const invs = wf.invocations || [];
  return (
    invs.find((i) => i.enabled !== false && i.kind === 'manual') ||
    invs.find((i) => i.enabled !== false && (i.kind === 'form' || i.kind === 'api'))
  );
}

function primaryKindLabel(kind: string): string {
  if (kind === 'form') return 'Formular';
  if (kind === 'manual') return 'Manuell';
  return kind;
}

export const GraphicalEditorWorkflowsTasksPage: React.FC = () => {
    const { t } = useLanguage();

  const instanceId = useInstanceId();
  const { request } = useApiRequest();
  const { showSuccess, showError } = useToast();
  const [tasks, setTasks] = useState<Automation2Task[]>([]);
  const [completedRuns, setCompletedRuns] = useState<CompletedRun[]>([]);
  const [startableWorkflows, setStartableWorkflows] = useState<Automation2Workflow[]>([]);
  const [loading, setLoading] = useState(true);
  const [completedExpanded, setCompletedExpanded] = useState(false);
  const [outputExpanded, setOutputExpanded] = useState(true);
  const [submitting, setSubmitting] = useState<string | null>(null);
  const [dismissingTaskId, setDismissingTaskId] = useState<string | null>(null);
  const [executingWorkflowId, setExecutingWorkflowId] = useState<string | null>(null);

  const load = useCallback(async () => {
    if (!instanceId) return;
    setLoading(true);
    try {
      const [taskList, runs] = await Promise.all([
        fetchTasks(request, instanceId),
        fetchCompletedRuns(request, instanceId, 20),
      ]);
      setTasks(taskList);
      setCompletedRuns(runs);
      try {
        const activeWfs = await fetchWorkflows(request, instanceId, { active: true });
        const list: Automation2Workflow[] = Array.isArray(activeWfs)
          ? activeWfs
          : (activeWfs && typeof activeWfs === 'object' && 'items' in activeWfs && Array.isArray((activeWfs as { items: Automation2Workflow[] }).items)
            ? (activeWfs as { items: Automation2Workflow[] }).items
            : []);
        setStartableWorkflows(
          list.filter(
            (w) => w.active !== false && hasManualOrFormInvocation(w)
          )
        );
      } catch (we) {
        console.error('[graphicalEditor] load startable workflows failed', we);
        setStartableWorkflows([]);
      }
    } catch (e) {
      console.error('[graphicalEditor] load failed', e);
    } finally {
      setLoading(false);
    }
  }, [instanceId, request]);

  useEffect(() => {
    load();
  }, [load]);

  const handleComplete = async (taskId: string, result: Record<string, unknown>) => {
    if (!instanceId) return;
    setSubmitting(taskId);
    try {
      await completeTask(request, instanceId, taskId, result);
      await load();
    } catch (e) {
      console.error('[graphicalEditor] complete failed', e);
    } finally {
      setSubmitting(null);
    }
  };

  const handleDismissOpenTask = async (taskId: string) => {
    if (!instanceId) return;
    setDismissingTaskId(taskId);
    try {
      const res = await cancelPendingTaskStopRun(request, instanceId, taskId);
      if (res.success) {
        showSuccess(t('Ausführung abgebrochen'));
        await load();
      } else {
        showError(t('Abbrechen fehlgeschlagen'));
      }
    } catch (e: unknown) {
      const msg =
        (e as { message?: string })?.message ?? t('Abbrechen fehlgeschlagen');
      showError(msg);
      console.error('[graphicalEditor] cancel task failed', e);
    } finally {
      setDismissingTaskId(null);
    }
  };

  const handleStartWorkflow = useCallback(
    async (wf: Automation2Workflow) => {
      if (!instanceId || !wf.graph) return;
      const primary = getPrimaryEntryPoint(wf);
      setExecutingWorkflowId(wf.id);
      try {
        const result = await executeGraph(request, instanceId, wf.graph, wf.id, {
          ...(primary ? { entryPointId: primary.id } : {}),
        });
        if (result?.success) {
          if (result?.paused) {
            showSuccess(t('Workflow gestartet und bei Human Task pausiert.'));
          } else {
            showSuccess(t('Workflow gestartet'));
          }
          await load();
        } else {
          showError(result?.error || t('Ausführung fehlgeschlagen'));
        }
      } catch (e: unknown) {
        const msg =
          (e as { message?: string })?.message ?? t('Ausführung fehlgeschlagen');
        showError(msg);
      } finally {
        setExecutingWorkflowId(null);
      }
    },
    [instanceId, request, showSuccess, showError, load, t]
  );

  const openTasks = tasks.filter((task) => task.status === 'pending');
  const completedTasks = tasks.filter((task) => task.status !== 'pending');

  if (!instanceId) {
    return (
      <div className={styles.placeholder}>
        <p>{t('keine Featureinstanz gefunden')}</p>
      </div>
    );
  }

  if (loading) {
    return (
      <div className={styles.loading}>
        <FaSpinner className={styles.spinner} />
        <p>{t('lade Tasks')}</p>
      </div>
    );
  }

  return (
    <div className={styles.pageLayout}>
      <div className={styles.mainColumn}>
        <div className={styles.container}>
      {/* Open tasks */}
      <section className={styles.section}>
        <h3 className={styles.sectionTitle}>
          {t('Offene Tasks')}
          {openTasks.length > 0 && <span className={styles.badge}>{openTasks.length}</span>}
        </h3>
        {openTasks.length === 0 ? (
          <p className={styles.empty}>{t('keine offenen Tasks')}</p>
        ) : (
          <div className={styles.taskList}>
            {openTasks.map((task) => (
              <TaskCard
                key={task.id}
                task={task}
                instanceId={instanceId ?? undefined}
                onSubmit={(result) => handleComplete(task.id, result)}
                submitting={submitting === task.id}
                showDismiss
                onDismiss={() => handleDismissOpenTask(task.id)}
                dismissing={dismissingTaskId === task.id}
              />
            ))}
          </div>
        )}
      </section>

      {/* Completed tasks */}
      <section className={styles.section}>
        <button
          type="button"
          className={styles.completedHeader}
          onClick={() => setCompletedExpanded((p) => !p)}
        >
          {completedExpanded ? <FaChevronDown /> : <FaChevronRight />}
          <span>{t('erledigte Tasks')}</span>
          {completedTasks.length > 0 && (
            <span className={styles.badge}>{completedTasks.length}</span>
          )}
        </button>
        {completedExpanded && (
          <div className={styles.completedList}>
            {completedTasks.length === 0 ? (
              <p className={styles.empty}>{t('keine erledigten Tasks')}</p>
            ) : (
              completedTasks.map((task) => (
                <TaskCard
                  key={task.id}
                  task={task}
                  instanceId={instanceId ?? undefined}
                  onSubmit={(result) => handleComplete(task.id, result)}
                  submitting={submitting === task.id}
                  readOnly
                />
              ))
            )}
          </div>
        )}
      </section>

      {/* Output – abgeschlossene Workflows mit Ergebnis */}
      <section className={styles.section}>
        <button
          type="button"
          className={styles.completedHeader}
          onClick={() => setOutputExpanded((p) => !p)}
        >
          {outputExpanded ? <FaChevronDown /> : <FaChevronRight />}
          <span>{t('Resultate')}</span>
          {completedRuns.length > 0 && (
            <span className={styles.badge}>{completedRuns.length}</span>
          )}
        </button>
        {outputExpanded && (
          <div className={styles.completedList}>
            {completedRuns.length === 0 ? (
              <p className={styles.empty}>
                {t('Keine abgeschlossenen Workflows. Führen Sie einen Workflow aus (z.B. im Editor), um hier die Ergebnisse zu sehen.')}
              </p>
            ) : (
              completedRuns.map((run) => (
                <OutputCard key={run.id} run={run} instanceId={instanceId ?? undefined} />
              ))
            )}
          </div>
        )}
      </section>
        </div>
      </div>

      <aside className={styles.startSidebar} aria-label={t('Workflows starten')}>
        <h3 className={styles.startSidebarTitle}>{t('Workflow starten')}</h3>
        <div className={styles.startSidebarList}>
          {startableWorkflows.length === 0 ? (
            <p className={styles.empty}>
              {t('Keine aktiven Workflows mit manuellem oder Formular-Start.')}
            </p>
          ) : (
            startableWorkflows.map((wf) => {
              const primary = getPrimaryEntryPoint(wf);
              const kind = primary?.kind ?? 'manual';
              return (
                <div key={wf.id} className={styles.startWorkflowRow}>
                  <div className={styles.startWorkflowInfo}>
                    <span className={styles.startWorkflowName} title={wf.label}>
                      {wf.label || wf.id}
                    </span>
                    <span className={styles.startWorkflowKind}>
                      {primaryKindLabel(kind)}
                    </span>
                  </div>
                  <button
                    type="button"
                    className={styles.startButton}
                    title={t('Workflow ausführen')}
                    disabled={executingWorkflowId === wf.id}
                    onClick={() => handleStartWorkflow(wf)}
                  >
                    {executingWorkflowId === wf.id ? (
                      <FaSpinner className={styles.spinner} />
                    ) : (
                      <FaPlay />
                    )}
                  </button>
                </div>
              );
            })
          )}
        </div>
      </aside>
    </div>
  );
};

/** Output card for completed workflow runs – zeigt nur die erstellten Dateien (mit fileId). */
const OutputCard: React.FC<{
  run: CompletedRun;
  instanceId?: string;
}> = ({ run }) => {
  const { t } = useLanguage();
  const ts = run.sysModifiedAt ?? run.sysCreatedAt ?? 0;
  const files: Array<{ name: string; fileId: string }> = [];
  const nodeOutputs = run.nodeOutputs ?? {};
  for (const [, out] of Object.entries(nodeOutputs)) {
    if (!out || typeof out !== 'object') continue;
    const o = out as Record<string, unknown>;
    const docs = (o.documents ?? o.documentList ?? []) as Array<Record<string, unknown>>;
    if (!Array.isArray(docs)) continue;
    for (const d of docs) {
      const fileId = (d.validationMetadata as Record<string, unknown>)?.fileId as string | undefined;
      if (fileId) {
        files.push({
          name: String(d.documentName ?? d.fileName ?? t('Datei')),
          fileId,
        });
      }
    }
  }
  return (
    <div className={styles.taskCard}>
      <div className={styles.taskMeta}>
        <div className={styles.taskMetaRow}>
          <span className={styles.metaLabel}>{t('Workflow')}</span>
          <span className={styles.metaValue}>{run.workflowLabel || run.workflowId || '—'}</span>
        </div>
        <div className={styles.taskMetaRow}>
          <span className={styles.metaLabel}>{t('Abgeschlossen')}</span>
          <span className={styles.metaValue}>{formatTimestamp(ts)}</span>
        </div>
      </div>
      {files.length > 0 ? (
        <div className={styles.outputContent}>
          <span className={styles.metaLabel}>{t('Dateien')}</span>
          <ul className={styles.uploadedList}>
            {files.map((f, j) => (
              <li key={j}>
                <Link
                  to="/basedata/files"
                  className={styles.downloadLink}
                >
                  {f.name}
                </Link>
              </li>
            ))}
          </ul>
        </div>
      ) : (
        <p className={styles.empty}>{t('kein Output, z.B. Workflow ohne')}</p>
      )}
    </div>
  );
};

interface TaskCardProps {
  task: Automation2Task;
  instanceId?: string;
  onSubmit: (result: Record<string, unknown>) => void;
  submitting: boolean;
  readOnly?: boolean;
  /** Open-task card: show top-right control to cancel run and remove from list. */
  showDismiss?: boolean;
  onDismiss?: () => void;
  dismissing?: boolean;
}

/** Check if file matches accept string (e.g. ".pdf,image/*"). */
function relationshipTaskIdFromFormValue(v: unknown): string {
  if (v && typeof v === 'object' && !Array.isArray(v) && 'add' in v) {
    const a = (v as { add?: unknown[] }).add;
    if (Array.isArray(a) && a[0] != null && String(a[0]).trim()) return String(a[0]);
  }
  return '';
}

function InputFormClickupTaskField({
  connectionId,
  listId,
  value,
  onChange,
  request,
}: {
  connectionId: string;
  listId: string;
  value: unknown;
  onChange: (v: unknown) => void;
  request: ApiRequestFunction;
}) {
  const { t } = useLanguage();
  const [tasks, setTasks] = useState<Array<{ id: string; name: string }>>([]);
  const [loading, setLoading] = useState(false);
  const [err, setErr] = useState<string | null>(null);

  useEffect(() => {
    const cid = connectionId.trim();
    const lid = listId.trim();
    if (!cid || !lid) {
      setTasks([]);
      return;
    }
    let cancelled = false;
    setLoading(true);
    setErr(null);
    loadClickupListTasksForDropdown(request, cid, lid)
      .then((rows) => {
        if (!cancelled) setTasks(rows);
      })
      .catch(() => {
        if (!cancelled) {
          setTasks([]);
          setErr(t('Aufgaben konnten nicht geladen werden.'));
        }
      })
      .finally(() => {
        if (!cancelled) setLoading(false);
      });
    return () => {
      cancelled = true;
    };
  }, [request, connectionId, listId]);

  const sel = relationshipTaskIdFromFormValue(value);

  if (!connectionId.trim() || !listId.trim()) {
    return (
      <p style={{ fontSize: '0.85rem', color: 'var(--text-secondary, #666)' }}>
        {t('Für dieses Feld sind im Formular-Node ClickUp-Verbindung und Listen-ID gesetzt — bitte Workflow prüfen.')}
      </p>
    );
  }

  return (
    <>
      {err ? (
        <p style={{ fontSize: '0.85rem', color: 'var(--text-secondary, #c00)' }}>{err}</p>
      ) : null}
      {loading ? (
        <p style={{ fontSize: '0.85rem', color: 'var(--text-secondary, #666)' }}>{t('lade Aufgaben')}</p>
      ) : (
        <select
          value={sel}
          onChange={(e) => {
            const tid = e.target.value;
            if (!tid) onChange({ add: [], rem: [] });
            else onChange({ add: [tid], rem: [] });
          }}
        >
          <option value="">{t('Aufgabe wählen')}</option>
          {tasks.map((taskRow) => (
            <option key={taskRow.id} value={taskRow.id}>
              {taskRow.name}
            </option>
          ))}
        </select>
      )}
    </>
  );
}

const TaskCard: React.FC<TaskCardProps> = ({
  task,
  instanceId,
  onSubmit,
  submitting,
  readOnly = false,
  showDismiss = false,
  onDismiss,
  dismissing = false,
}) => {
  const { t } = useLanguage();
  const { request } = useApiRequest();
  const { handleFileUpload } = useFileOperations();
  const [formData, setFormData] = useState<Record<string, unknown>>({});
  const [formPopupOpen, setFormPopupOpen] = useState(false);
  const [uploadedFiles, setUploadedFiles] = useState<Array<{ id: string; fileName: string; file?: Record<string, unknown> }>>([]);
  const [uploading, setUploading] = useState(false);
  const [uploadError, setUploadError] = useState<string | null>(null);
  const fileInputRef = useRef<HTMLInputElement>(null);
  const config = task.config ?? {};
  const nodeType = task.nodeType;
  const stepLabel = getNodeStepLabel(config);

  useEffect(() => {
    setUploadedFiles([]);
    setUploadError(null);
  }, [task.id]);

  const renderInput = () => {
    if (readOnly) return null;
    switch (nodeType) {
      case 'input.form': {
        const fields =
          (config.fields as Array<{
            name: string;
            type: string;
            label: string;
            required?: boolean;
            options?: unknown;
            clickupConnectionId?: string;
            clickupListId?: string;
            clickupStatusOptions?: Array<{ value: string; label: string }>;
          }>) ?? [];
        const requiredFields = fields.filter((f) => f.required);
        const allRequiredFilled = requiredFields.every((f) => {
          const v = formData[f.name];
          if (f.type === 'boolean') return true;
          if (f.type === 'clickup_tasks') {
            return relationshipTaskIdFromFormValue(v) !== '';
          }
          if (f.type === 'clickup_status') {
            return v !== undefined && v !== null && String(v).trim() !== '';
          }
          if ((f.type === 'select' || f.type === 'enum') && normalizeFormFieldOptions(f.options).some((o) => String(o.value).trim() !== '')) {
            return v !== undefined && v !== null && String(v).trim() !== '';
          }
          return v !== undefined && v !== null && String(v).trim() !== '';
        });
        const renderFormControl = (
          field: (typeof fields)[number],
        ): React.ReactNode => {
          const selectChoices = normalizeFormFieldOptions(field.options).filter(
            (o) => String(o.value).trim() !== '',
          );
          if (field.type === 'boolean') {
            return (
              <input
                type="checkbox"
                checked={(formData[field.name] as boolean) ?? false}
                onChange={(e) =>
                  setFormData((p) => ({ ...p, [field.name]: e.target.checked }))
                }
              />
            );
          }
          if (field.type === 'clickup_tasks' && request) {
            return (
              <InputFormClickupTaskField
                connectionId={field.clickupConnectionId ?? ''}
                listId={field.clickupListId ?? ''}
                value={formData[field.name]}
                onChange={(v) => setFormData((p) => ({ ...p, [field.name]: v }))}
                request={request}
              />
            );
          }
          if (
            field.type === 'clickup_status' &&
            Array.isArray(field.clickupStatusOptions) &&
            field.clickupStatusOptions.length > 0
          ) {
            return (
              <select
                value={(formData[field.name] as string) ?? ''}
                onChange={(e) =>
                  setFormData((p) => ({ ...p, [field.name]: e.target.value }))
                }
              >
                <option value="">{t('Status wählen')}</option>
                {field.clickupStatusOptions.map((o) => (
                  <option key={o.value} value={o.value}>
                    {o.label}
                  </option>
                ))}
              </select>
            );
          }
          if ((field.type === 'select' || field.type === 'enum') && selectChoices.length > 0) {
            return (
              <select
                value={(formData[field.name] as string) ?? ''}
                onChange={(e) =>
                  setFormData((p) => ({ ...p, [field.name]: e.target.value }))
                }
              >
                <option value="">{t('Bitte wählen')}</option>
                {selectChoices.map((o) => (
                  <option key={o.value} value={o.value}>
                    {o.label || o.value}
                  </option>
                ))}
              </select>
            );
          }
          return (
            <input
              type={
                field.type === 'number' ? 'number' : field.type === 'date' ? 'date' : 'text'
              }
              value={(formData[field.name] as string) ?? ''}
              onChange={(e) =>
                setFormData((p) => ({ ...p, [field.name]: e.target.value }))
              }
            />
          );
        };
        const formContent = (
          <div className={styles.formFields}>
            {fields.map((f) => (
              <div key={f.name}>
                <label>
                  {f.label || f.name}
                  {f.required && ' *'}
                </label>
                {renderFormControl(f)}
              </div>
            ))}
          </div>
        );
        return (
          <>
            <button
              type="button"
              onClick={() => setFormPopupOpen(true)}
              disabled={submitting}
              className={styles.openFormButton}
            >
              Formular bearbeiten
            </button>
            <Popup
              isOpen={formPopupOpen}
              title={t('Formular ausfüllen')}
              onClose={() => setFormPopupOpen(false)}
              size="medium"
              footerContent={
                <button
                  type="button"
                  onClick={() => {
                    // Match node output shape used by refs (payload.*) and outputPreviewRegistry.input.form
                    onSubmit({ payload: formData });
                    setFormPopupOpen(false);
                  }}
                  disabled={submitting || !allRequiredFilled}
                  className={styles.popupSubmitButton}
                >
                  {submitting ? t('wird gesendet') : t('absenden')}
                </button>
              }
            >
              {formContent}
            </Popup>
          </>
        );
      }
      case 'input.approval':
        return (
          <div>
            {config.title != null && String(config.title) !== '' && <h4>{String(config.title)}</h4>}
            {config.description != null && String(config.description) !== '' && <p>{String(config.description)}</p>}
            <div className={styles.approvalButtons}>
              <button
                type="button"
                onClick={() => onSubmit({ approved: true })}
                disabled={submitting}
              >
                {t('Genehmigen')}
              </button>
              <button
                type="button"
                onClick={() => onSubmit({ approved: false })}
                disabled={submitting}
              >
                {t('Ablehnen')}
              </button>
            </div>
          </div>
        );
      case 'input.comment':
        return (
          <div>
            <textarea
              placeholder={(config.placeholder as string) ?? t('Kommentar...')}
              value={(formData.comment as string) ?? ''}
              onChange={(e) => setFormData({ comment: e.target.value })}
            />
            <button
              type="button"
              onClick={() => onSubmit(formData)}
              disabled={
                submitting ||
                ((config.required !== false) && !formData.comment)
              }
            >
              {t('Absenden')}
            </button>
          </div>
        );
      case 'input.selection': {
        const options =
          (config.options as Array<{ value: string; label: string }>) ?? [];
        const multiple = config.multiple as boolean;
        return (
          <div>
            {options.map((o) => (
              <label key={o.value}>
                <input
                  type={multiple ? 'checkbox' : 'radio'}
                  name={task.id}
                  value={o.value}
                  onChange={(e) => {
                    if (multiple) {
                      const prev = (formData.selected as string[]) ?? [];
                      const next = e.target.checked
                        ? [...prev, o.value]
                        : prev.filter((v) => v !== o.value);
                      setFormData((p) => ({ ...p, selected: next }));
                    } else {
                      setFormData((p) => ({ ...p, selected: o.value }));
                    }
                  }}
                />
                {o.label || o.value}
              </label>
            ))}
            <button
              type="button"
              onClick={() => onSubmit(formData)}
              disabled={submitting}
            >
              {t('Absenden')}
            </button>
          </div>
        );
      }
      case 'input.confirmation':
        return (
          <div>
            <p>{(config.question as string) ?? t('Bestätigen?')}</p>
            <div className={styles.approvalButtons}>
              <button
                type="button"
                onClick={() => onSubmit({ confirmed: true })}
                disabled={submitting}
              >
                {typeof config.confirmLabel === 'string' ? config.confirmLabel : t('Bestätigen')}
              </button>
              <button
                type="button"
                onClick={() => onSubmit({ confirmed: false })}
                disabled={submitting}
              >
                {typeof config.rejectLabel === 'string' ? config.rejectLabel : t('Ablehnen')}
              </button>
            </div>
          </div>
        );
      case 'input.upload': {
        const acceptStr = getAcceptStringFromConfig(config);
        const maxSizeMB = (config.maxSize as number) ?? 10;
        const allowMultiple = (config.multiple as boolean) ?? false;
        const maxSizeBytes = maxSizeMB * 1024 * 1024;

        const handleFileSelect = async (e: React.ChangeEvent<HTMLInputElement>) => {
          const files = e.target.files;
          if (!files?.length || !instanceId) return;
          if (!allowMultiple && files.length > 1) {
            setUploadError('Nur eine Datei erlaubt.');
            return;
          }
          setUploadError(null);
          setUploading(true);
          const results: Array<{ id: string; fileName: string; file?: Record<string, unknown> }> = [];
          for (let i = 0; i < files.length; i++) {
            const file = files[i];
            if (file.size > maxSizeBytes) {
              setUploadError(`Datei "${file.name}" zu groß (max. ${maxSizeMB} MB).`);
              setUploading(false);
              e.target.value = '';
              return;
            }
            if (acceptStr && acceptStr !== '*' && !fileMatchesAccept(file, acceptStr)) {
              setUploadError(
                `Die Datei „${file.name}“ hat ein nicht erlaubtes Format. Bitte eine Datei mit passender Endung verwenden (laut Upload-Schritt im Workflow).`,
              );
              setUploading(false);
              e.target.value = '';
              return;
            }
            try {
              const result = await handleFileUpload(
                file,
                task.workflowId ?? undefined,
                instanceId ?? undefined
              );
              if (result?.success && result?.fileData) {
                const fileMeta = result.fileData?.file ?? result.fileData;
                const fileId = fileMeta?.id ?? fileMeta?.fileName;
                if (fileId) {
                  results.push({
                    id: fileId,
                    fileName: fileMeta?.fileName ?? file.name,
                    file: fileMeta,
                  });
                }
              } else if (result?.error) {
                setUploadError(result.error);
                setUploading(false);
                e.target.value = '';
                return;
              }
            } catch (err: unknown) {
              const msg = (err as { response?: { data?: { detail?: string } }; message?: string })?.response?.data?.detail ?? (err as Error)?.message ?? t('Upload fehlgeschlagen');
              setUploadError(msg);
              setUploading(false);
              e.target.value = '';
              return;
            }
          }
          setUploadedFiles((prev) => (allowMultiple ? [...prev, ...results] : results));
          setUploading(false);
          e.target.value = '';
        };

        const handleSubmitUpload = () => {
          if (uploadedFiles.length === 0) {
            setUploadError(t('Bitte mindestens eine Datei hochladen.'));
            return;
          }
          const file = uploadedFiles[0]?.file ?? { id: uploadedFiles[0]?.id, fileName: uploadedFiles[0]?.fileName };
          const files = uploadedFiles.map((u) => u.file ?? { id: u.id, fileName: u.fileName });
          const fileIds = uploadedFiles.map((u) => u.id);
          onSubmit({
            file,
            files,
            fileIds,
          });
        };

        return (
          <div className={styles.uploadTaskBlock}>
            <input
              ref={fileInputRef}
              type="file"
              accept={acceptStr === '*' ? undefined : acceptStr || undefined}
              multiple={allowMultiple}
              onChange={handleFileSelect}
              style={{ display: 'none' }}
            />
            <button
              type="button"
              onClick={() => fileInputRef.current?.click()}
              disabled={submitting || uploading}
              className={styles.uploadButton}
            >
              <FaUpload /> {uploading ? t('wird hochgeladen') : t('Dateien auswählen')}
            </button>
            {uploadError && <p className={styles.uploadError}>{uploadError}</p>}
            {uploadedFiles.length > 0 && (
              <ul className={styles.uploadedList}>
                {uploadedFiles.map((u) => (
                  <li key={u.id}>{u.fileName}</li>
                ))}
              </ul>
            )}
            <button
              type="button"
              onClick={handleSubmitUpload}
              disabled={submitting || uploading || uploadedFiles.length === 0}
              className={styles.popupSubmitButton}
            >
              {submitting ? t('wird gesendet') : t('absenden')}
            </button>
          </div>
        );
      }
      case 'input.review':
        return (
          <div>
            <p>{t('Review-Inhalt anzeigen, Feedback')}</p>
            <textarea
              placeholder={t('Feedback…')}
              value={(formData.feedback as string) ?? ''}
              onChange={(e) => setFormData({ feedback: e.target.value })}
            />
            <button
              type="button"
              onClick={() => onSubmit(formData)}
              disabled={submitting}
            >
              {t('Absenden')}
            </button>
          </div>
        );
      default:
        return (
          <div>
            <p>{t('Unbekannter Task-Typ: {typ}', { typ: String(nodeType) })}</p>
            <button
              type="button"
              onClick={() => onSubmit({})}
              disabled={submitting}
            >
              {t('Absenden')}
            </button>
          </div>
        );
    }
  };

  const cardClass = showDismiss
    ? `${styles.taskCard} ${styles.taskCardDismissable}`
    : styles.taskCard;

  return (
    <div className={cardClass}>
      {showDismiss && onDismiss ? (
        <button
          type="button"
          className={styles.dismissOpenTaskBtn}
          title={t('Task entfernen und Ausführung abbrechen')}
          aria-label={t('Task entfernen und Ausführung abbrechen')}
          disabled={submitting || dismissing}
          onClick={(e) => {
            e.stopPropagation();
            onDismiss();
          }}
        >
          {dismissing ? <FaSpinner className={styles.spinner} /> : <FaTimes />}
        </button>
      ) : null}
      <div className={styles.taskMeta}>
        <div className={styles.taskMetaRow}>
          <span className={styles.metaLabel}>{t('Workflow')}</span>
          <span className={styles.metaValue}>
            {task.workflowLabel || task.workflowId || '—'}
          </span>
        </div>
        <div className={styles.taskMetaRow}>
          <span className={styles.metaLabel}>{t('erstellt')}</span>
          <span className={styles.metaValue}>
            {formatTimestamp(task.createdAt)}
          </span>
        </div>
        <div className={styles.taskMetaRow}>
          <span className={styles.metaLabel}>{t('fällig')}</span>
          <span className={styles.metaValue}>
            {formatTimestamp(task.dueAt)}
          </span>
        </div>
        {stepLabel && (
          <div className={styles.taskMetaRow}>
            <span className={styles.metaLabel}>{t('Schritt')}</span>
            <span className={styles.metaValue}>{stepLabel}</span>
          </div>
        )}
        <div className={styles.taskMetaRow}>
          <span className={styles.metaLabel}>{t('Typ')}</span>
          <span className={styles.metaValue}>
            {_nodeTypeLabel(nodeType, t)}
          </span>
        </div>
        
      </div>
      {renderInput()}
    </div>
  );
};
