// TruckOrderDelivery.jsx — per-vendor delivery logging on the iPad.
// Mirrors the portal version (portal/components/TruckOrderDelivery.jsx)
// — same Supabase Storage flow + truck_order_deliveries row schema —
// adapted to iPad-shared Icon/Btn components and touch-first sizing.

const INVOICE_BUCKET_IPAD = 'truck-invoices';

async function getOrCreateDeliveryIpad(orderId, vendorId) {
  if (!window.supa) return null;
  const restId = window.RESTAURANT_ID;
  const { data: existing, error: e1 } = await window.supa
    .from('truck_order_deliveries')
    .select('*')
    .eq('order_id', orderId)
    .eq('vendor_id', vendorId)
    .maybeSingle();
  if (e1) { console.error('delivery lookup failed', e1); return null; }
  if (existing) return existing;
  const { data: created, error: e2 } = await window.supa
    .from('truck_order_deliveries')
    .insert({ order_id: orderId, vendor_id: vendorId, restaurant_id: restId })
    .select()
    .single();
  if (e2) { console.error('delivery create failed', e2); return null; }
  return created;
}

async function uploadInvoicePhotoIpad(delivery, file) {
  const restId = window.RESTAURANT_ID;
  const ext = (file.name.split('.').pop() || 'jpg')
    .toLowerCase()
    .replace(/[^a-z0-9]/g, '') || 'jpg';
  const uuid = crypto.randomUUID
    ? crypto.randomUUID()
    : (Date.now() + '-' + Math.random().toString(36).slice(2));
  const key = `${restId}/${delivery.order_id}/${delivery.vendor_id}/${delivery.id}/${uuid}.${ext}`;
  const { error } = await window.supa.storage
    .from(INVOICE_BUCKET_IPAD)
    .upload(key, file, {
      contentType: file.type || 'image/' + ext,
      upsert: false,
    });
  if (error) throw error;
  return key;
}

function ipadPublicUrl(key) {
  if (!window.supa || !key) return '';
  return window.supa.storage.from(INVOICE_BUCKET_IPAD).getPublicUrl(key).data.publicUrl;
}

async function setPhotoKeysIpad(deliveryId, keys) {
  await window.supa
    .from('truck_order_deliveries')
    .update({ photo_keys: keys, updated_at: new Date().toISOString() })
    .eq('id', deliveryId);
}

// Kick the extract-invoice Edge Function. Fire-and-forget — realtime
// delivers ai_status / results back. We optimistically flip the row
// to 'queued' so the UI updates immediately.
async function triggerExtractIpad(deliveryId) {
  if (!window.supa || !deliveryId) return;
  await window.supa.from('truck_order_deliveries')
    .update({ ai_status: 'queued', ai_error: null })
    .eq('id', deliveryId);
  void window.supa.functions
    .invoke('extract-invoice', { body: { delivery_id: deliveryId } })
    .catch(err => console.warn('extract-invoice invoke failed', err));
}

const TruckDeliveryPanelIpad = ({ order, vendor, currentStaff, showToast }) => {
  const [delivery, setDelivery] = useState(null);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState('');
  const [previewKey, setPreviewKey] = useState(null);
  const fileInputRef = useRef(null);
  const cameraInputRef = useRef(null);

  useEffect(() => {
    let cancelled = false;
    (async () => {
      const d = await getOrCreateDeliveryIpad(order.id, vendor.id);
      if (!cancelled) setDelivery(d);
    })();
    if (!window.supa) return;
    const ch = window.supa
      .channel(`ipad-delivery:${order.id}:${vendor.id}`)
      .on('postgres_changes', {
        event: '*', schema: 'public', table: 'truck_order_deliveries',
        filter: 'order_id=eq.' + order.id,
      }, (payload) => {
        const r = payload.new || payload.old;
        if (!r || r.vendor_id !== vendor.id) return;
        if (payload.eventType === 'DELETE') return;
        setDelivery(r);
      })
      .subscribe();
    return () => { cancelled = true; window.supa.removeChannel(ch); };
  }, [order.id, vendor.id]);

  const handleFiles = async (fileList) => {
    if (!fileList || fileList.length === 0 || !delivery) return;
    setError(''); setBusy(true);
    try {
      const files = Array.from(fileList);
      const keys = [];
      for (const f of files) {
        const k = await uploadInvoicePhotoIpad(delivery, f);
        keys.push(k);
      }
      const merged = [...(delivery.photo_keys || []), ...keys];
      await setPhotoKeysIpad(delivery.id, merged);
      if (!delivery.received_by_staff_id && currentStaff?.id) {
        await window.supa
          .from('truck_order_deliveries')
          .update({ received_by_staff_id: currentStaff.id })
          .eq('id', delivery.id);
      }
      setDelivery(d => d ? { ...d, photo_keys: merged } : d);
      showToast && showToast({
        message: keys.length === 1 ? 'Invoice photo uploaded' : `${keys.length} photos uploaded`,
        icon: 'check', staff: currentStaff || undefined,
      });
      // NOTE: extraction is NOT auto-kicked on the iPad — cameras shoot one
      // photo at a time, so auto-triggering would start the AI run on a
      // partial invoice. The user taps "Run AI extraction" in the panel
      // below once every page has been captured.
    } catch (e) {
      setError(e?.message || 'Upload failed.');
      showToast && showToast({ message: 'Upload failed — try again', icon: 'x' });
    } finally {
      setBusy(false);
      if (fileInputRef.current) fileInputRef.current.value = '';
      if (cameraInputRef.current) cameraInputRef.current.value = '';
    }
  };

  const removePhoto = async (k) => {
    if (!delivery) return;
    if (!confirm('Remove this photo?')) return;
    const next = (delivery.photo_keys || []).filter(x => x !== k);
    await setPhotoKeysIpad(delivery.id, next);
    // Storage DELETE is admin-only; iPad just drops the reference. The
    // orphan file in storage is harmless and the admin portal can clean
    // it up later if needed.
    setDelivery(d => d ? { ...d, photo_keys: next } : d);
  };

  const photos = delivery?.photo_keys || [];

  return (
    <div style={{
      padding: '12px 14px',
      background: '#FBFAF8',
      borderTop: '1px solid var(--border-2)',
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 10 }}>
        <Icon name="download" size={14} color="var(--fg-2)" strokeWidth={2} />
        <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--fg-1)' }}>
          Delivery
        </div>
        {photos.length > 0 && (
          <span style={{
            fontSize: 11, fontWeight: 600, padding: '2px 8px', borderRadius: 999,
            background: '#DCFCE7', color: '#166534',
          }}>{photos.length} {photos.length === 1 ? 'photo' : 'photos'}</span>
        )}
        <div style={{ flex: 1 }} />
        <input
          ref={cameraInputRef}
          type="file"
          accept="image/*"
          capture="environment"
          multiple
          style={{ display: 'none' }}
          onChange={(e) => handleFiles(e.target.files)}
        />
        <input
          ref={fileInputRef}
          type="file"
          accept="image/*,.pdf"
          multiple
          style={{ display: 'none' }}
          onChange={(e) => handleFiles(e.target.files)}
        />
        <Btn variant="primary" size="sm" disabled={busy || !delivery}
          onClick={() => cameraInputRef.current?.click()}>
          <Icon name="eye" size={13} color="#FFFFFF" strokeWidth={2} />
          Take photo
        </Btn>
        <Btn variant="secondary" size="sm" disabled={busy || !delivery}
          onClick={() => fileInputRef.current?.click()}
          style={{ marginLeft: 6 }}>
          Upload
        </Btn>
      </div>

      {error && (
        <div style={{ fontSize: 12, color: '#B91C1C', marginBottom: 8 }}>{error}</div>
      )}

      {photos.length === 0 ? (
        <div style={{
          padding: '24px 14px', textAlign: 'center',
          fontSize: 13, color: 'var(--fg-3)',
          border: '1px dashed var(--border-1)', borderRadius: 10,
          background: '#FFFFFF',
        }}>
          {busy ? 'Uploading…' : 'Tap Take photo to capture the invoice page-by-page.'}
        </div>
      ) : (
        <div style={{
          display: 'grid',
          gridTemplateColumns: 'repeat(auto-fill, minmax(120px, 1fr))',
          gap: 10,
        }}>
          {photos.map(k => (
            <div key={k} style={{ position: 'relative' }}>
              <button
                onClick={() => setPreviewKey(k)}
                style={{
                  display: 'block', padding: 0, border: '1px solid var(--border-2)',
                  borderRadius: 10, overflow: 'hidden', background: '#FFFFFF', width: '100%',
                }}
              >
                <img
                  src={ipadPublicUrl(k)}
                  alt="invoice"
                  style={{ display: 'block', width: '100%', aspectRatio: '1 / 1', objectFit: 'cover' }}
                />
              </button>
              <button
                onClick={() => removePhoto(k)}
                style={{
                  position: 'absolute', top: 5, right: 5,
                  width: 26, height: 26, borderRadius: 999,
                  background: 'rgba(0,0,0,0.7)', color: '#FFFFFF',
                  display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                  border: 'none', cursor: 'pointer',
                }}
              ><Icon name="x" size={13} color="#fff" strokeWidth={2.4} /></button>
            </div>
          ))}
        </div>
      )}

      {delivery && photos.length > 0 && (
        <IpadAiResultsPanel
          delivery={delivery}
          onRerun={() => triggerExtractIpad(delivery.id)}
        />
      )}

      {previewKey && (
        <div
          onClick={() => setPreviewKey(null)}
          style={{
            position: 'fixed', inset: 0,
            background: 'rgba(0,0,0,0.86)', zIndex: 1000,
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            padding: 32,
          }}
        >
          <img
            src={ipadPublicUrl(previewKey)}
            alt="invoice"
            style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }}
            onClick={e => e.stopPropagation()}
          />
        </div>
      )}
    </div>
  );
};

// ------------------------------------------------------------------
// Inline AI results — read-only on iPad. Price-change acceptance
// happens in the portal (admin write to inventory_items).
// ------------------------------------------------------------------
const IpadAiResultsPanel = ({ delivery, onRerun }) => {
  const status = delivery.ai_status;
  const disc = delivery.ai_discrepancies || {};
  const missing = disc.missing || [];
  const extra = disc.extra || [];
  const prices = disc.price_changes || [];
  const conf = typeof delivery.ai_match_confidence === 'number' ? delivery.ai_match_confidence : null;
  const trusted = delivery.confirmed_match || (conf !== null && conf >= 0.9);

  let badgeBg = '#E5E7EB', badgeFg = '#374151';
  if (conf !== null) {
    if (conf >= 0.85)      { badgeBg = '#DCFCE7'; badgeFg = '#166534'; }
    else if (conf >= 0.55) { badgeBg = '#FEF3C7'; badgeFg = '#92400E'; }
    else                   { badgeBg = '#FEE2E2'; badgeFg = '#991B1B'; }
  }

  return (
    <div style={{
      marginTop: 12, padding: 12,
      background: '#FFFFFF', border: '1px solid var(--border-2)',
      borderRadius: 12,
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
        <Icon name="star" size={13} color="#7C3AED" strokeWidth={2.4} />
        <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--fg-1)' }}>AI invoice match</div>
        {status === 'done' && conf !== null && (
          <span style={{
            fontSize: 11, fontWeight: 700,
            padding: '2px 8px', borderRadius: 999,
            background: badgeBg, color: badgeFg,
            fontFamily: 'var(--font-num)', letterSpacing: '0.02em',
          }}>{Math.round(conf * 100)}% match</span>
        )}
        <div style={{ flex: 1 }} />
        {/* Pending = first run. Manual button so the camera-shoot-one-page-
            at-a-time flow doesn't kick the AI on a partial invoice. */}
        {status === 'pending' && (
          <button onClick={onRerun} style={{
            display: 'inline-flex', alignItems: 'center', gap: 6,
            fontSize: 13, fontWeight: 600, color: '#FFFFFF',
            padding: '7px 14px', borderRadius: 8,
            background: 'var(--fg-1)', border: 'none',
            cursor: 'pointer',
          }}>
            <Icon name="star" size={13} color="#FFFFFF" strokeWidth={2.4} />
            Run AI extraction
          </button>
        )}
        {(status === 'done' || status === 'error') && (
          <button onClick={onRerun} style={{
            fontSize: 12, color: 'var(--fg-2)',
            padding: '4px 10px', borderRadius: 6,
            background: 'var(--bg-sunken)', border: 'none',
          }}>Re-run</button>
        )}
      </div>

      <div style={{ marginTop: 8, fontSize: 13, color: 'var(--fg-2)' }}>
        {ipadAiStatusLine(delivery)}
      </div>

      {status === 'done' && conf !== null && conf < 0.9 && !delivery.confirmed_match && (
        <div style={{
          marginTop: 10, padding: '10px 12px',
          background: conf < 0.55 ? '#FEE2E2' : '#FEF3C7',
          border: '1px solid ' + (conf < 0.55 ? '#FCA5A5' : '#FDE68A'),
          borderRadius: 8,
        }}>
          <div style={{ fontSize: 13, fontWeight: 700, color: conf < 0.55 ? '#991B1B' : '#92400E' }}>
            {conf < 0.55 ? 'This may be the wrong invoice' : 'Borderline match — admin review needed'}
          </div>
          <div style={{ fontSize: 12.5, color: conf < 0.55 ? '#991B1B' : '#92400E', marginTop: 4, opacity: 0.9, lineHeight: 1.4 }}>
            Open the admin portal to confirm or discard. iPad is read-only for this gate.
          </div>
        </div>
      )}

      {status === 'done' && (missing.length + extra.length + prices.length > 0) && (
        <div style={{ marginTop: 12, display: 'flex', flexDirection: 'column', gap: 8 }}>
          {missing.length > 0 && (
            <IpadDiscBlock
              tone="red"
              title="Missing from delivery"
              hint="Ordered but not seen on the invoice."
              rows={missing.map(m => `${m.name} — ordered ${m.ordered} ${m.purchase_unit || ''}`.trim())}
            />
          )}
          {extra.length > 0 && (
            <IpadDiscBlock
              tone="amber"
              title="Extra on invoice"
              hint="Lines we couldn't match to anything you ordered."
              rows={extra.map(x => `${x.name} — ${x.qty}${x.unit_price != null ? ' @ $' + x.unit_price : ''}`)}
            />
          )}
          {prices.length > 0 && (
            <IpadDiscBlock
              tone="amber"
              title="Price changes"
              hint="Open the portal to accept; iPad is read-only for inventory pricing."
              rows={prices.map(p => `${p.name}: ${p.old_price != null ? '$' + p.old_price : '—'} → $${p.new_price}`)}
            />
          )}
        </div>
      )}
    </div>
  );
};

const IpadDiscBlock = ({ tone, title, hint, rows }) => {
  const palette = tone === 'red'
    ? { bg: '#FEF2F2', border: '#FCA5A5', fg: '#991B1B' }
    : { bg: '#FFFBEB', border: '#FDE68A', fg: '#92400E' };
  return (
    <div style={{
      padding: '8px 10px',
      background: palette.bg,
      border: '1px solid ' + palette.border,
      borderRadius: 8,
    }}>
      <div style={{ fontSize: 11.5, fontWeight: 700, color: palette.fg, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
        {title} ({rows.length})
      </div>
      <div style={{ fontSize: 12, color: palette.fg, marginTop: 2, opacity: 0.85 }}>{hint}</div>
      <ul style={{ margin: '6px 0 0', padding: '0 0 0 18px', fontSize: 12.5, color: palette.fg, lineHeight: 1.6 }}>
        {rows.map((r, i) => <li key={i}>{r}</li>)}
      </ul>
    </div>
  );
};

function ipadAiStatusLine(d) {
  switch (d.ai_status) {
    case 'pending':    return 'Ready when you are — tap Run AI extraction after every invoice page has been captured.';
    case 'queued':     return 'Queued — extraction starting…';
    case 'processing': return 'Reading the invoice (typically 5–30s)…';
    case 'done': {
      const disc = d.ai_discrepancies || {};
      const missing = (disc.missing || []).length;
      const extra   = (disc.extra   || []).length;
      const prices  = (disc.price_changes || []).length;
      if (missing === 0 && extra === 0 && prices === 0) return '✓ All ordered items delivered, no price changes.';
      const parts = [];
      if (missing) parts.push(`${missing} missing`);
      if (extra)   parts.push(`${extra} extra`);
      if (prices)  parts.push(`${prices} price change${prices === 1 ? '' : 's'}`);
      return parts.join(' · ');
    }
    case 'error':      return 'Extraction failed — ' + (d.ai_error || 'unknown error');
    default:           return d.ai_status;
  }
}

Object.assign(window, { TruckDeliveryPanelIpad });
