// ─────────────────────────────────────────────
// DO_Fields_Text.jsx
// TextareaField, NumberField
// Requires: DO_Shared.jsx (S, BORDER, TEXT, FieldLabel)
// ─────────────────────────────────────────────

const MAX_TEXTAREA_EM = 20;

// ─────────────────────────────────────────────
// TEXTAREA FIELD (single + multi-line text)
// ─────────────────────────────────────────────
function TextareaField({ obj, value, onChange, onBlur }) {
  const h        = parseInt(obj.height) || 1;
  const isSingle = h <= 1;
  const heightEm = Math.min(h * 1.2, MAX_TEXTAREA_EM);
  const maxLen   = obj.maxlength ? parseInt(obj.maxlength) : null;
  const charCount= (value || "").length;
  const nearLimit= maxLen && charCount > maxLen * 0.85;
  const atLimit  = maxLen && charCount >= maxLen;

  return (
    <div style={S.fieldWrap}>
      <FieldLabel obj={obj} />
      <textarea
        style={{
          ...S.input,
          height:     isSingle ? "2.2em" : `${heightEm}em`,
          resize:     isSingle ? "none"  : "vertical",
          overflow:   isSingle ? "hidden" : "auto",
          lineHeight: "1.2em",
          minHeight:  "2.2em",
          maxHeight:  `${MAX_TEXTAREA_EM}em`,
          borderColor: atLimit ? "#ef4444" : nearLimit ? "#f59e0b" : undefined,
        }}
        value={value || ""}
        maxLength={maxLen || undefined}
        placeholder={obj.placeholder || ""}
        onChange={e => onChange(obj.field, e.target.value)}
        onBlur={onBlur ? () => onBlur(obj.field) : undefined}
        rows={1}
      />
      {maxLen && (
        <div style={{
          ...S.fieldHint,
          textAlign: "right",
          color: atLimit ? "#ef4444" : nearLimit ? "#f59e0b" : "#64748b"
        }}>
          {charCount} / {maxLen}
        </div>
      )}
    </div>
  );
}

// ─────────────────────────────────────────────
// NUMBER FIELD
// - type="text" inputMode="decimal" for full control
// - Blocks non-numeric input on change
// - Clamps to min/max and rounds to decimals on blur
// - Reverts to last valid DB value if invalid on blur
// ─────────────────────────────────────────────
function NumberField({ obj, value, onChange, onBlur }) {
  const decimals  = parseInt(obj.decimals ?? 0);
  const format    = obj.format || '';
  const currSym   = obj.currencySymbol || '$';
  const prefix    = format === 'currency' ? currSym : (obj.prefix || '');
  const suffix    = format === 'percent'  ? '%'     : (obj.suffix || '');
  const align     = obj.align || 'right';
  const minVal    = obj.min !== undefined && obj.min !== '' ? parseFloat(obj.min) : null;
  const maxVal    = obj.max !== undefined && obj.max !== '' ? parseFloat(obj.max) : null;

  // Local display state — lets user type freely, reverts on invalid blur
  const [display, setDisplay] = React.useState(value || '');

  // Sync display when external value changes (record navigation)
  React.useEffect(() => { setDisplay(value || ''); }, [value]);

  function handleChange(e) {
    const raw = e.target.value;
    // Allow partial input while typing
    if (raw === '' || raw === '-' || raw === '.' || raw === '-.') {
      setDisplay(raw);
      return;
    }
    // Accept only valid numeric strings — fire onChange so save triggers
    if (!isNaN(raw) && raw.trim() !== '') {
      setDisplay(raw);
      onChange(obj.field, raw);
    }
    // Silently ignore anything else (letters etc)
  }

  function handleBlur() {
    let v = parseFloat(display);
    if (isNaN(v)) {
      // Invalid — revert to last known good value from DB
      setDisplay(value || '');
      if (onBlur) onBlur(obj.field);
      return;
    }
    if (minVal !== null && v < minVal) v = minVal;
    if (maxVal !== null && v > maxVal) v = maxVal;
    if (decimals === 0) v = Math.round(v);
    else v = parseFloat(v.toFixed(decimals));
    const final = String(v);
    setDisplay(final);
    if (final !== display) onChange(obj.field, final);
    if (onBlur) onBlur(obj.field);
  }

  return (
    <div style={S.fieldWrap}>
      <FieldLabel obj={obj} />
      <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
        {prefix && <span style={S.fieldAffix}>{prefix}</span>}
        <input
          type="text"
          inputMode="decimal"
          style={{ ...S.input, textAlign: align }}
          value={display}
          placeholder={obj.placeholder || ''}
          onChange={handleChange}
          onBlur={handleBlur}
        />
        {suffix && <span style={S.fieldAffix}>{suffix}</span>}
      </div>
    </div>
  );
}
