// js/components/pages/ReceberFrete.jsx
// FRT-C3 (2026-05-09) — Receber frete (visão Abbes/estoquista) MOBILE-FIRST.
// Fluxo: lista notas em rota → seleciona → recebe items → handle leftovers/surprise/loss.
// Roles: estoquista, admin. Privacy: estoquista NÃO vê unit_cost_usd.
//        Sempre lê de v_freight_note_items_for_warehouse (VIEW sem custo).
// Deps runtime: sb, toast, Modal, Icon (globals)
(function() {
  'use strict';
  const {useState, useEffect, useMemo, useCallback, useRef} = React;

  // ══════════════════════════════════════════════════════════════
  // HELPERS — [Wave 14 v223.39] REUSO Wave 13 freight-helpers.js + statusBadge agora widget
  // ══════════════════════════════════════════════════════════════
  // fmtShortDate, genIdem → window.ZNX.lib.freight (Wave 13)
  // statusBadge → <FreightNoteStatusBadge status=.../> (window.FreightNoteStatusBadge — diferente Wave 13 FreightStatusBadge)
  const _freightLib = (window.ZNX && window.ZNX.lib && window.ZNX.lib.freight) || {};
  const fmtShortDate = _freightLib.fmtShortDate;
  const genIdem = _freightLib.genIdem;
  if (typeof fmtShortDate !== 'function' || typeof genIdem !== 'function') {
    console.error('[ZNX v223.39] freight-helpers.js Wave 13 não carregou — ReceberFrete broken');
  }

  // ══════════════════════════════════════════════════════════════
  // COMPONENTE PRINCIPAL
  // ══════════════════════════════════════════════════════════════

  function ReceberFrete({ user }) {
    // === Hooks (TODOS antes de early return) ===
    const [carriers, setCarriers] = useState([]);
    const [products, setProducts] = useState([]);
    const [notes, setNotes] = useState([]);
    const [items, setItems] = useState([]); // VIEW v_freight_note_items_for_warehouse
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);

    const [view, setView] = useState('list'); // 'list' | 'receive'
    const [selectedNoteId, setSelectedNoteId] = useState(null); // regra_state_id_vs_objeto
    const [filterCarrier, setFilterCarrier] = useState('');

    // Recebimento — qty por item-id
    const [qtyToAdd, setQtyToAdd] = useState({}); // { [itemId]: '5' }
    const [submitting, setSubmitting] = useState(false);

    // Modais secundários
    const [modalLeftover, setModalLeftover] = useState(null); // { product_id, leftover, applied }
    const [modalSurprise, setModalSurprise] = useState(false);
    const [modalLoss, setModalLoss] = useState(false);

    // [Wave 14 v223.39] surpriseForm + lossForm extracted to SkuSurpriseModal + RequestLossModal (state interno)
    const [actionInFlight, setActionInFlight] = useState(false);

    const isEstoquista = user?.role === 'estoquista';
    const canReceive = user?.role === 'admin' || user?.role === 'estoquista';

    // === Loaders ===
    const loadAll = useCallback(async () => {
      if (typeof sb === 'undefined' || !sb.from) return;
      setLoading(true);
      setError(null);
      try {
        // Estoquista usa VIEW (sem unit_cost_usd) — admin pode usar a tabela direto mas pra
        // consistência usamos a VIEW pra ambos. Privacy 2 camadas mantida.
        const [c, p, n, i] = await Promise.all([
          sb.from('freight_carriers').select('id,name,active').is('deleted_at', null).order('name'),
          sb.from('products').select('id,name,brand,volume,categoria').is('deleted_at', null).eq('active', true).order('name').limit(2000),
          sb.from('freight_notes').select('id,number,carrier_id,status,emitted_at,confirmed_carrier_at,exchange_rate_usd_brl,notes')
            .is('deleted_at', null)
            .in('status', ['EM_TRANSITO', 'EM_RECEBIMENTO'])
            .order('emitted_at', { ascending: true }),
          sb.from('v_freight_note_items_for_warehouse').select('*').limit(5000),
        ]);
        if (c.error) throw c.error;
        if (p.error) throw p.error;
        if (n.error) throw n.error;
        if (i.error) throw i.error;
        setCarriers(c.data || []);
        setProducts(p.data || []);
        setNotes(n.data || []);
        setItems(i.data || []);
      } catch (e) {
        console.error('[ReceberFrete] load error:', e);
        setError(e?.message || String(e));
        if (typeof Sentry !== 'undefined') Sentry.captureException(e, { extra: { context: 'ReceberFrete.loadAll' } });
      } finally {
        setLoading(false);
      }
    }, []);

    useEffect(() => {
      // [v224.72] cancelled flag preventivo · full fix = passar cancelled pra loadAll (deferred)
      let cancelled = false;
      loadAll();
      return () => { cancelled = true; };
    }, [loadAll]);

    // === Derivados ===
    const carrierMap = useMemo(() => Object.fromEntries(carriers.map(c => [c.id, c])), [carriers]);
    const productMap = useMemo(() => Object.fromEntries(products.map(p => [p.id, p])), [products]);

    const filteredNotes = useMemo(() => {
      let list = notes;
      if (filterCarrier) list = list.filter(n => n.carrier_id === filterCarrier);
      return list;
    }, [notes, filterCarrier]);

    // Lookup nota selecionada
    const selectedNote = useMemo(
      () => selectedNoteId ? notes.find(n => n.id === selectedNoteId) : null,
      [selectedNoteId, notes]
    );
    const selectedItems = useMemo(
      () => selectedNote ? items.filter(i => i.note_id === selectedNote.id) : [],
      [selectedNote, items]
    );

    // Total qty pendente (faltando) na nota selecionada
    const totalMissing = useMemo(
      () => selectedItems.reduce((s, i) => s + Math.max(0, Number(i.expected_qty || 0) - Number(i.received_qty || 0)), 0),
      [selectedItems]
    );

    // Total qty que o user vai adicionar nesse batch
    const batchTotal = useMemo(
      () => Object.values(qtyToAdd).reduce((s, v) => s + (Number(v) || 0), 0),
      [qtyToAdd]
    );

    // === Handlers ===
    function openNote(note) {
      setSelectedNoteId(note.id);
      setQtyToAdd({});
      setView('receive');
    }
    function backToList() {
      setView('list');
      setSelectedNoteId(null);
      setQtyToAdd({});
      loadAll(); // reload pra refletir status atualizado
    }

    async function handleStartReceiving() {
      if (!selectedNote || actionInFlight) return;
      if (selectedNote.status !== 'EM_TRANSITO') return;
      setActionInFlight(true);
      try {
        const idem = genIdem();
        const { data, error } = await sb.rpc('start_receiving_v1', {
          p_note_id: selectedNote.id,
          p_idempotency_key: idem,
        });
        if (error) throw error;
        if (!data?.success) throw new Error(data?.error_message || 'Falha');
        toast('✅ Recebimento iniciado');
        await loadAll();
      } catch (e) {
        toast('❌ ' + (e?.message || 'Erro'), 'error');
        if (typeof Sentry !== 'undefined') Sentry.captureException(e, { extra: { context: 'ReceberFrete.handleStartReceiving' } });
      } finally {
        setActionInFlight(false);
      }
    }

    async function handleSubmitBatch() {
      if (!selectedNote || submitting) return;
      // Filtra items com qty>0
      const toSend = Object.entries(qtyToAdd)
        .map(([itemId, qty]) => {
          const it = selectedItems.find(i => i.id === itemId);
          return it && Number(qty) > 0 ? { product_id: it.product_id, qty_received: Number(qty), itemId } : null;
        })
        .filter(Boolean);
      if (toSend.length === 0) {
        toast('Adicione qty em ao menos 1 item', 'error');
        return;
      }
      setSubmitting(true);
      try {
        const idem = genIdem();
        const { data, error } = await sb.rpc('register_freight_entry_v1', {
          payload: {
            idempotency_key: idem,
            carrier_id: selectedNote.carrier_id,
            items: toSend.map(({ product_id, qty_received }) => ({ product_id, qty_received })),
          },
        });
        if (error) throw error;
        if (!data?.success) throw new Error(data?.error_message || 'Falha ao registrar entrada');

        // Detecta leftovers (qty_received > soma cabia nas notas)
        const leftovers = (data.applied || []).filter(a => Number(a.leftover_qty) > 0);
        if (leftovers.length > 0) {
          const lo = leftovers[0]; // mostra primeiro (raro ter múltiplos)
          setModalLeftover({
            product_id: lo.product_id,
            leftover: lo.leftover_qty,
            applied: lo.applied_to_notes || [],
          });
          toast(`⚠️ Sobrou ${lo.leftover_qty} un. — escolha ação`);
        } else {
          toast(`✅ Entrada registrada (${toSend.length} item${toSend.length > 1 ? 's' : ''})`);
          if ((data.completed_notes || []).length > 0) {
            toast(`🎉 Nota ${selectedNote.number} COMPLETA!`);
          }
        }

        // Reload + clear
        setQtyToAdd({});
        await loadAll();
      } catch (e) {
        console.error('[ReceberFrete] submit error:', e);
        toast('❌ ' + (e?.message || 'Erro inesperado'), 'error');
        if (typeof Sentry !== 'undefined') Sentry.captureException(e, { extra: { context: 'ReceberFrete.handleSubmitBatch' } });
      } finally {
        setSubmitting(false);
      }
    }

    // ══════ Modal Leftover (4 ações) ══════
    async function handleLeftoverAction(action) {
      if (!modalLeftover || actionInFlight) return;
      if (action === 'recount') {
        // No-op server-side. Apenas fecha e deixa user contar de novo no campo qty.
        toast('🔢 Recount manual — ajuste a qty no item e re-submit');
        setModalLeftover(null);
        return;
      }
      if (action === 'accept_and_return') {
        toast('Devolução com retorno: virá em onda futura. Use "Bloquear" por enquanto.', 'error');
        return;
      }
      // accept_real ou block_pending
      setActionInFlight(true);
      try {
        const idem = genIdem();
        const { data, error } = await sb.rpc('register_freight_entry_extra_v1', {
          payload: {
            idempotency_key: idem,
            action,
            note_id: selectedNote.id,
            product_id: modalLeftover.product_id,
            qty_extra: modalLeftover.leftover,
            reason: action === 'block_pending' ? 'Excesso de qty no recebimento' : null,
          },
        });
        if (error) throw error;
        if (!data?.success) throw new Error(data?.error_message || 'Falha');
        if (action === 'accept_real') toast('✅ Aceito qty real');
        else if (action === 'block_pending') toast('⏸️ Bloqueado pra admin decidir');
        setModalLeftover(null);
        await loadAll();
      } catch (e) {
        toast('❌ ' + (e?.message || 'Erro'), 'error');
        if (typeof Sentry !== 'undefined') Sentry.captureException(e, { extra: { context: 'ReceberFrete.handleLeftoverAction', action } });
      } finally {
        setActionInFlight(false);
      }
    }

    // ══════ Modal SKU Surprise — [Wave 14 v223.39] form state interno SkuSurpriseModal.jsx ══════
    function openSurpriseModal() {
      setModalSurprise(true);
    }
    async function handleSubmitSurprise(form) {
      if (actionInFlight) return;
      if (!form.product_id) { toast('Selecione o SKU', 'error'); return; }
      if (Number(form.qty) <= 0) { toast('Qty > 0', 'error'); return; }
      const evidenceArr = (form.evidence || '').split(/[\n,]/).map(s => s.trim()).filter(Boolean);
      if (evidenceArr.length === 0) { toast('Adicione ao menos 1 URL/descrição de evidência', 'error'); return; }
      setActionInFlight(true);
      try {
        const idem = genIdem();
        const { data, error } = await sb.rpc('register_sku_surprise_v1', {
          payload: {
            idempotency_key: idem,
            note_id: selectedNote.id,
            product_id: form.product_id,
            qty: Number(form.qty),
            reason: form.reason || null,
            evidence_photos: evidenceArr,
          },
        });
        if (error) throw error;
        if (!data?.success) throw new Error(data?.error_message || 'Falha');
        toast('✅ SKU surpresa enviado pra admin decidir');
        setModalSurprise(false);
        await loadAll();
      } catch (e) {
        toast('❌ ' + (e?.message || 'Erro'), 'error');
        if (typeof Sentry !== 'undefined') Sentry.captureException(e, { extra: { context: 'ReceberFrete.handleSubmitSurprise' } });
      } finally {
        setActionInFlight(false);
      }
    }

    // ══════ Modal Solicitar fechamento com perda — [Wave 14 v223.39] form state interno RequestLossModal.jsx ══════
    function openLossModal() {
      setModalLoss(true);
    }
    async function handleSubmitLoss(form) {
      if (actionInFlight) return;
      const evidenceArr = (form.evidence || '').split(/[\n,]/).map(s => s.trim()).filter(Boolean);
      if (evidenceArr.length === 0) { toast('Adicione ao menos 1 URL/descrição de evidência', 'error'); return; }
      setActionInFlight(true);
      try {
        const idem = genIdem();
        const { data, error } = await sb.rpc('request_close_with_loss_v1', {
          payload: {
            idempotency_key: idem,
            note_id: selectedNote.id,
            reason: form.reason || null,
            evidence_photos: evidenceArr,
          },
        });
        if (error) throw error;
        if (!data?.success) throw new Error(data?.error_message || 'Falha');
        toast(`✅ Pedido enviado (${data.loss_qty_total} un. faltando)`);
        setModalLoss(false);
        // Volta pra lista (nota não pode mais receber)
        backToList();
      } catch (e) {
        toast('❌ ' + (e?.message || 'Erro'), 'error');
        if (typeof Sentry !== 'undefined') Sentry.captureException(e, { extra: { context: 'ReceberFrete.handleSubmitLoss' } });
      } finally {
        setActionInFlight(false);
      }
    }

    // === Privacy guard ===
    if (!canReceive) {
      return (
        <div style={{ padding: 40, textAlign: 'center' }}>
          <div style={{ fontSize: 48, marginBottom: 10 }}>🔒</div>
          <div style={{ fontSize: 18, fontWeight: 700, color: '#B91C1C' }}>Acesso restrito</div>
          <div style={{ fontSize: 13, color: '#6B7280', marginTop: 6 }}>
            Apenas estoquista e admin podem receber frete.
          </div>
        </div>
      );
    }

    // ══════════════════════════════════════════════════════════════
    // RENDER — view='list'
    // ══════════════════════════════════════════════════════════════

    if (view === 'list') {
      return (
        <FreightNoteList
          filteredNotes={filteredNotes}
          items={items}
          carriers={carriers}
          carrierMap={carrierMap}
          filterCarrier={filterCarrier}
          setFilterCarrier={setFilterCarrier}
          loading={loading}
          error={error}
          onOpenNote={openNote}
        />
      );
    }

    // ══════════════════════════════════════════════════════════════
    // RENDER — view='receive' (recebimento da nota selecionada)
    // ══════════════════════════════════════════════════════════════

    if (view === 'receive' && selectedNote) {
      return (
        <>
          <ReceiveBatchView
            selectedNote={selectedNote}
            selectedItems={selectedItems}
            productMap={productMap}
            carrierMap={carrierMap}
            qtyToAdd={qtyToAdd} setQtyToAdd={setQtyToAdd}
            batchTotal={batchTotal} totalMissing={totalMissing}
            actionInFlight={actionInFlight} submitting={submitting}
            onBack={backToList}
            onStartReceiving={handleStartReceiving}
            onSubmitBatch={handleSubmitBatch}
            onOpenSurprise={openSurpriseModal}
            onOpenLoss={openLossModal}
          />
          <LeftoverActionModal
            modalLeftover={modalLeftover}
            productMap={productMap}
            actionInFlight={actionInFlight}
            onAction={handleLeftoverAction}
            onClose={() => setModalLeftover(null)}
          />
          <SkuSurpriseModal
            show={modalSurprise}
            products={products}
            selectedNote={selectedNote}
            actionInFlight={actionInFlight}
            onSubmit={handleSubmitSurprise}
            onClose={() => setModalSurprise(false)}
          />
          <RequestLossModal
            show={modalLoss}
            totalMissing={totalMissing}
            actionInFlight={actionInFlight}
            onSubmit={handleSubmitLoss}
            onClose={() => setModalLoss(false)}
          />
        </>
      );
    }

    // Fallback (não deveria chegar)
    return null;
  }

  // [Wave 14 v223.39] Field movido pra SkuSurpriseModal.jsx + RequestLossModal.jsx (uso local nos widgets)

  // ══════════════════════════════════════════════════════════════
  // EXPORT
  // ══════════════════════════════════════════════════════════════
  window.ZNX = window.ZNX || {};
  window.ZNX.components = window.ZNX.components || {};
  window.ZNX.components.ReceberFrete = ReceberFrete;
  window.ReceberFrete = ReceberFrete;

  window.ZNX.refactor_phase_6_loaded = window.ZNX.refactor_phase_6_loaded || {};
  window.ZNX.refactor_phase_6_loaded.ReceberFrete = true;
})();
