// Copyright (c) 2026 PowerOn AG
// All rights reserved.
/**
 * RequiredAttributePicker — Phase-4 Schicht-4 binding affordance for
 * required parameters of a Schicht-3 Adapter (Editor-Node).
 *
 * 0/1/N logic, applied on the set of typed source candidates:
 *   - 0 candidates  → red pill: "Keine typkompatible Quelle vorhanden"
 *                     (user must add an upstream node first)
 *   - 1 candidate   → auto-bound chip with a "Andere wählen…" override button
 *                     (still shown explicitly so the user sees what was chosen)
 *   - N candidates  → "Quelle wählen…" button that opens the DataPicker
 *                     pre-filtered to the expected type
 *
 * The picker also surfaces a "Iterieren als Loop" hint when the expected type
 * is `X` and an upstream candidate is `List[X]` — see paramValidation.ts.
 */

import React, { useMemo, useState } from 'react';
import { useWorkflowDataFlow } from '../../context/WorkflowDataFlowContext';
import { DataPicker } from './DataPicker';
import { createRef, formatRefLabel, isRef, type DataRef, type SystemVarRef } from './dataRef';
import { findSourceCandidates, strictlyCompatible, type SourceCandidate } from './paramValidation';
import styles from '../../editor/WorkflowFlowEditor.module.css';

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

export interface RequiredAttributePickerProps {
  /** Display label for the parameter (already localized). */
  label: string;
  /** Type expected by the bound action argument (e.g. "DocumentList", "str"). */
  expectedType?: string;
  /** Current bound value (DataRef, SystemVarRef, or unset). */
  value: unknown;
  /** Persist a new binding (or `null` to clear). */
  onChange: (next: DataRef | SystemVarRef | null) => void;
  /** Optional description shown beneath the picker. */
  description?: React.ReactNode;
}

export const RequiredAttributePicker: React.FC<RequiredAttributePickerProps> = ({
  label,
  expectedType,
  value,
  onChange,
  description,
}) => {
  const { t } = useLanguage();
  const ctx = useWorkflowDataFlow();
  const [pickerOpen, setPickerOpen] = useState(false);

  const consumerNodeId = ctx?.currentNodeId ?? '';
  const nodes = ctx?.nodes ?? [];
  const connections = ctx?.connections ?? [];
  const nodeTypes = ctx?.nodeTypes ?? [];
  const catalog = ctx?.portTypeCatalog ?? {};

  const allCandidates: SourceCandidate[] = useMemo(() => {
    if (!consumerNodeId) return [];
    return findSourceCandidates({
      consumerNodeId,
      expectedType,
      nodes,
      connections: connections.map((c) => ({
        id: c.id,
        sourceId: c.sourceId,
        sourceHandle: c.sourceHandle,
        targetId: c.targetId,
        targetHandle: c.targetHandle,
      })),
      nodeTypes,
      portTypeCatalog: catalog,
    });
  }, [consumerNodeId, expectedType, nodes, connections, nodeTypes, catalog]);

  const compatibleCandidates = useMemo(() => strictlyCompatible(allCandidates), [allCandidates]);

  const isBoundRef = isRef(value);
  const boundLabel = isBoundRef ? formatRefLabel(value as DataRef, nodes) : null;

  // 0/1/N
  const candidateCount = compatibleCandidates.length;
  const single = candidateCount === 1 ? compatibleCandidates[0] : null;

  const handleAutoBind = () => {
    if (!single) return;
    const ref = createRef(single.nodeId, single.iterable && expectedType ? [...single.path, '*'] : single.path, expectedType);
    onChange(ref);
  };

  const handlePicked = (picked: DataRef | SystemVarRef) => {
    onChange(picked);
  };

  return (
    <div
      className={styles.requiredAttributePicker}
      style={{
        display: 'flex',
        flexDirection: 'column',
        gap: 4,
        minWidth: 0,
        maxWidth: '100%',
      }}
    >
      {/* Header: label always takes the full row (flex-basis 100 %), badge
          wraps below — prevents long type names like List[ActionDocument]
          from escaping the panel frame on the right. */}
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 6, flexWrap: 'wrap' }}>
        <label
          style={{
            fontSize: 12,
            fontWeight: 600,
            flex: '1 1 100%',
            minWidth: 0,
            overflowWrap: 'anywhere',
            wordBreak: 'break-word',
          }}
        >
          {label}
          <span style={{ color: 'var(--danger-color, #dc3545)', marginLeft: 2 }}>*</span>
        </label>
        {expectedType && (
          <span
            title={t('Erwarteter Typ')}
            style={{
              fontSize: 10,
              fontFamily: 'monospace',
              color: 'var(--text-secondary, #555)',
              background: 'var(--bg-secondary, #eee)',
              border: '1px solid var(--border-color, #e0e0e0)',
              borderRadius: 4,
              padding: '1px 6px',
              maxWidth: '100%',
              overflow: 'hidden',
              textOverflow: 'ellipsis',
              whiteSpace: 'nowrap',
            }}
          >
            {expectedType}
          </span>
        )}
      </div>

      {isBoundRef ? (
        <div style={{ display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap', minWidth: 0 }}>
          <span
            title={typeof boundLabel === 'string' ? boundLabel : undefined}
            style={{
              padding: '2px 8px',
              borderRadius: 12,
              background: 'rgba(40,167,69,0.15)',
              color: 'var(--success-color, #28a745)',
              fontSize: 12,
              fontWeight: 500,
              maxWidth: '100%',
              overflowWrap: 'anywhere',
              wordBreak: 'break-word',
              lineHeight: 1.4,
            }}
          >
            {boundLabel}
          </span>
          <button
            type="button"
            className={styles.retryButton}
            onClick={() => setPickerOpen(true)}
            style={{ fontSize: 11, padding: '2px 8px', flexShrink: 0 }}
          >
            {t('Andere wählen…')}
          </button>
          <button
            type="button"
            className={styles.retryButton}
            onClick={() => onChange(null)}
            style={{ fontSize: 11, padding: '2px 8px', flexShrink: 0 }}
            title={t('Bindung entfernen')}
          >
            ×
          </button>
        </div>
      ) : candidateCount === 0 ? (
        <div
          style={{
            display: 'flex',
            alignItems: 'flex-start',
            gap: 6,
            padding: '4px 8px',
            background: 'rgba(220,53,69,0.12)',
            color: 'var(--danger-color, #dc3545)',
            borderRadius: 6,
            fontSize: 12,
            minWidth: 0,
            overflowWrap: 'anywhere',
            wordBreak: 'break-word',
          }}
        >
          <span aria-hidden="true" style={{ flexShrink: 0 }}>⚠</span>
          <span style={{ minWidth: 0 }}>
            {t('Keine typkompatible Quelle vorhanden — füge zuerst einen Knoten ein, der ')}
            <code style={{ fontFamily: 'monospace', overflowWrap: 'anywhere' }}>{expectedType ?? '?'}</code>
            {t(' liefert.')}
          </span>
        </div>
      ) : single ? (
        <div style={{ display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap', minWidth: 0 }}>
          <button
            type="button"
            className={styles.retryButton}
            onClick={handleAutoBind}
            style={{
              fontSize: 11,
              padding: '3px 10px',
              maxWidth: '100%',
              whiteSpace: 'normal',
              textAlign: 'left',
              overflowWrap: 'anywhere',
              wordBreak: 'break-word',
              lineHeight: 1.4,
            }}
            title={t('Einzige passende Quelle übernehmen')}
          >
            {t('Vorschlag übernehmen:')}{' '}
            <strong>
              {nodes.find((n) => n.id === single.nodeId)?.title ?? single.nodeId}
              {single.path.length > 0 ? ' → ' + single.path.map(String).join(' → ') : ''}
              {single.iterable ? ' [' + t('iterieren') + ']' : ''}
            </strong>
          </button>
          <button
            type="button"
            className={styles.retryButton}
            onClick={() => setPickerOpen(true)}
            style={{ fontSize: 11, padding: '3px 10px', flexShrink: 0 }}
          >
            {t('Andere…')}
          </button>
        </div>
      ) : (
        <div style={{ display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap', minWidth: 0 }}>
          <button
            type="button"
            className={styles.retryButton}
            onClick={() => setPickerOpen(true)}
            style={{ fontSize: 11, padding: '3px 10px', maxWidth: '100%' }}
          >
            {t('Quelle wählen…')} <span style={{ opacity: 0.6 }}>({candidateCount})</span>
          </button>
        </div>
      )}

      {description && (
        <div
          style={{
            fontSize: 11,
            color: 'var(--text-tertiary, #888)',
            overflowWrap: 'anywhere',
            wordBreak: 'break-word',
          }}
        >
          {description}
        </div>
      )}

      {pickerOpen && (
        <DataPicker
          open={pickerOpen}
          onClose={() => setPickerOpen(false)}
          onPick={(picked) => {
            handlePicked(picked);
            setPickerOpen(false);
          }}
          availableSourceIds={ctx?.getAvailableSourceIds() ?? []}
          nodes={nodes}
          nodeOutputsPreview={ctx?.nodeOutputsPreview ?? {}}
          getNodeLabel={(n) =>
            ctx?.getNodeLabel(n as { id: string; title?: string; label?: string; type?: string }) ?? n.id
          }
          expectedParamType={expectedType}
        />
      )}
    </div>
  );
};
