/* global React */
const { useState, useEffect, useRef, useCallback, useMemo } = React;

// =====================================================================
// Ícones (stroke SVG, inline)
// =====================================================================
const Ico = ({ d, size = 14, className = 'ico' }) => (
  <svg className={className} width={size} height={size} viewBox="0 0 24 24" aria-hidden="true">
    <path d={d}></path>
  </svg>
);
const IcoCart = (p) => <Ico {...p} d="M3 4h2l2 12h11l2-8H7M9 20a1 1 0 100 2 1 1 0 000-2zm9 0a1 1 0 100 2 1 1 0 000-2z" />;
const IcoBox = (p) => <Ico {...p} d="M3 7l9-4 9 4-9 4-9-4zm0 0v10l9 4 9-4V7" />;
const IcoClock = (p) => <Ico {...p} d="M12 7v5l3 2m6-2a9 9 0 11-18 0 9 9 0 0118 0z" />;
const IcoStack = (p) => <Ico {...p} d="M3 7l9-4 9 4-9 4-9-4zm0 5l9 4 9-4M3 17l9 4 9-4" />;
const IcoSliders = (p) => <Ico {...p} d="M4 6h13m4 0h-1M4 12h5m12 0H13M4 18h13m4 0h-1M14 4v4m-9 6v4m12-4v4" />;
const IcoMap = (p) => <Ico {...p} d="M9 4l-6 2v14l6-2 6 2 6-2V4l-6 2-6-2zm0 0v14m6-12v14" />;
const IcoPlus = (p) => <Ico {...p} d="M12 5v14m-7-7h14" />;
const IcoX = (p) => <Ico {...p} d="M6 6l12 12M18 6L6 18" />;
const IcoSave = (p) => <Ico {...p} d="M5 5v14a1 1 0 001 1h12a1 1 0 001-1V7l-3-3H6a1 1 0 00-1 1zm5 2h4m-7 8h12" />;
const IcoDownload = (p) => <Ico {...p} d="M12 4v12m-5-5l5 5 5-5M4 20h16" />;
const IcoUpload = (p) => <Ico {...p} d="M12 20V8m-5 5l5-5 5 5M4 4h16" />;
const IcoRefresh = (p) => <Ico {...p} d="M4 4v6h6M20 20v-6h-6M5 14a8 8 0 0014 4M19 10a8 8 0 00-14-4" />;
const IcoTrash = (p) => <Ico {...p} d="M4 7h16M9 7V5a2 2 0 012-2h2a2 2 0 012 2v2m1 0v12a2 2 0 01-2 2H9a2 2 0 01-2-2V7" />;
const IcoEye = (p) => <Ico {...p} d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12zm10 3a3 3 0 100-6 3 3 0 000 6z" />;
const IcoFile = (p) => <Ico {...p} d="M14 3H6a2 2 0 00-2 2v14a2 2 0 002 2h12a2 2 0 002-2V9zm0 0v6h6" />;
const IcoSparkle = (p) => <Ico {...p} d="M12 3v3m0 12v3m-9-9H6m12 0h3M5.6 5.6l2.1 2.1m8.6 8.6l2.1 2.1M5.6 18.4l2.1-2.1m8.6-8.6l2.1-2.1" />;
const IcoLogout = (p) => <Ico {...p} d="M15 4h4a2 2 0 012 2v12a2 2 0 01-2 2h-4M10 17l-5-5 5-5M5 12h11" />;

window.Icons = { IcoCart, IcoBox, IcoClock, IcoStack, IcoSliders, IcoMap,
                 IcoPlus, IcoX, IcoSave, IcoDownload, IcoUpload, IcoRefresh,
                 IcoTrash, IcoEye, IcoFile, IcoSparkle, IcoLogout };

// =====================================================================
// Tooltip (hover sobre .tip)
// =====================================================================
function Tooltip({ children, text }) {
  const [show, setShow] = useState(false);
  const [pos, setPos] = useState({ x: 0, y: 0 });
  const ref = useRef();
  const onEnter = (e) => {
    const r = e.currentTarget.getBoundingClientRect();
    setPos({ x: r.left + r.width/2, y: r.top });
    setShow(true);
  };
  return (
    <>
      <span ref={ref} className="tip" onMouseEnter={onEnter} onMouseLeave={() => setShow(false)} tabIndex={0}>?</span>
      {show && (
        <div style={{
          position: 'fixed',
          left: pos.x, top: pos.y - 10,
          transform: 'translate(-50%, -100%)',
          background: '#08090b',
          color: 'var(--text)',
          border: '1px solid var(--border-strong)',
          borderRadius: 8,
          padding: '9px 12px',
          fontSize: 11.5,
          maxWidth: 280,
          lineHeight: 1.5,
          zIndex: 9999,
          boxShadow: 'var(--sh-3)',
          pointerEvents: 'none',
          fontFamily: 'var(--font-sans)',
          fontWeight: 400,
        }}>{text}</div>
      )}
    </>
  );
}
window.Tooltip = Tooltip;

// =====================================================================
// Segmented (Sim/Não toggle moderno)
// =====================================================================
function Segmented({ value, options, onChange, full = true }) {
  return (
    <div className={`segmented ${full ? 'full' : ''}`}>
      {options.map(o => (
        <button
          key={o.value}
          className={`seg-btn ${value === o.value ? 'active' : ''}`}
          onClick={() => onChange(o.value)}
          type="button">
          {o.label}
        </button>
      ))}
    </div>
  );
}
window.Segmented = Segmented;

// =====================================================================
// Toast
// =====================================================================
function ToastHost({ toast }) {
  if (!toast) return null;
  return (
    <div className={`toast show ${toast.kind || ''}`}>
      {toast.kind === 'ok' && <IcoSparkle size={13} />}
      {toast.msg}
    </div>
  );
}
window.ToastHost = ToastHost;

// =====================================================================
// NumInput: input numérico tolerante (aceita vírgula, ponto e milhar BR)
//
// Correção importante:
// - O texto digitado fica em estado local enquanto o campo está em edição.
// - O componente só sincroniza com o valor externo quando o usuário NÃO está
//   digitando. Isso evita o efeito de “digitei, saí do campo e voltou para 0”.
// - No blur, o valor confirmado é mantido visualmente e enviado ao pai sem
//   depender da ordem de renderização do React.
// =====================================================================
const OBJ_STR_RE = /\[object[^\]]*\]/g;
const isCorrupt = (s) => typeof s === 'string' && s.includes('[object');

function parseLocaleNumber(raw) {
  if (raw === null || raw === undefined) return null;
  if (typeof raw === 'number') return isFinite(raw) ? raw : null;

  let s = String(raw)
    .replace(OBJ_STR_RE, '')
    .replace(/R\$|%/g, '')
    .replace(/\s+/g, '')
    .trim();

  if (!s || s === '-' || s === ',' || s === '.' || s === '-,' || s === '-.') return null;

  const hasComma = s.includes(',');
  const hasDot = s.includes('.');

  if (hasComma && hasDot) {
    // O último separador digitado é tratado como decimal.
    if (s.lastIndexOf(',') > s.lastIndexOf('.')) {
      s = s.replace(/\./g, '').replace(',', '.'); // 19.813,24 -> 19813.24
    } else {
      s = s.replace(/,/g, ''); // 19,813.24 -> 19813.24
    }
  } else if (hasComma) {
    s = s.replace(',', '.');
  } else if (hasDot) {
    // 19.813 deve ser aceito como milhar BR; 19.8 como decimal.
    const sign = s.startsWith('-') ? '-' : '';
    const body = sign ? s.slice(1) : s;
    if (/^\d{1,3}(\.\d{3})+$/.test(body)) s = sign + body.replace(/\./g, '');
  }

  const n = Number(s);
  return Number.isFinite(n) ? n : null;
}

function numToDraft(value) {
  if (value === null || value === undefined || value === '') return '';
  const n = parseLocaleNumber(value);
  return n === null ? '' : String(n);
}

function NumInput({ value, onChange, ...rest }) {
  const [draft, setDraft] = useState(() => numToDraft(value));
  const [editing, setEditing] = useState(false);
  const committedRef = useRef(null);

  const emit = useCallback((n) => {
    if (typeof onChange === 'function') onChange(n);
  }, [onChange]);

  useEffect(() => {
    if (editing) return;

    const external = parseLocaleNumber(value);
    const committed = committedRef.current;

    // Após blur, pode existir um render intermediário com o valor antigo do pai.
    // Nesse caso, preserva o texto confirmado em vez de voltar ao valor anterior.
    if (committed !== null) {
      if (external === null || Math.abs(external - committed) > 0.0000001) return;
      committedRef.current = null;
    }

    setDraft(numToDraft(value));
  }, [value, editing]);

  const safeDraft = (typeof draft === 'string' ? draft : '').replace(OBJ_STR_RE, '');

  return (
    <input
      type="text"
      inputMode="decimal"
      {...rest}
      value={safeDraft}
      className={`mono ${rest.className || ''}`.trim()}
      autoComplete="off"
      autoCorrect="off"
      autoCapitalize="off"
      spellCheck={false}
      data-1p-ignore="true"
      data-lpignore="true"
      data-bwignore="true"
      data-form-type="other"
      onFocus={() => setEditing(true)}
      onBlur={() => {
        const num = parseLocaleNumber(safeDraft);
        setEditing(false);

        if (num === null) {
          committedRef.current = 0;
          setDraft(numToDraft(0));
          emit(0);
          return;
        }

        committedRef.current = num;
        setDraft(numToDraft(num));
        emit(num);
      }}
      onChange={(ev) => {
        const text = ev.target.value;
        if (isCorrupt(text)) {
          setDraft('');
          return;
        }

        setDraft(text);

        const num = parseLocaleNumber(text);
        // Atualiza o estado do pai sempre que o texto já representa um número.
        // O draft local preserva formatos intermediários como "12," enquanto digita.
        if (num !== null) emit(num);
      }}
    />
  );
}
window.NumInput = NumInput;
window.__isCorrupt = isCorrupt;
window.__parseLocaleNumber = parseLocaleNumber;
