/* ═══════════════════════════════════════════════════════════════════
   OperationStatusPill.jsx — Inline plugin operation status (Option B)
   Session: 2026-05-18, fifteenth pass
   ═══════════════════════════════════════════════════════════════════
   Reusable React component. Drop into any feature page to surface
   plugin write-back status next to its "Apply to WP" button.

   Usage:
     <window.OperationStatusPill operationId={opId} onComplete={() => ...} />

   Props:
     operationId   — UUID of pending_operations row to track. Required.
     pollInterval  — ms between status polls. Default 4000.
                     Bumps to 1500 once in_progress for snappier UX.
     onComplete    — fired once when status becomes terminal (completed
                     | failed | cancelled | expired). Receives final
                     operation object.

   The pill auto-stops polling once status is terminal — no leaks.

   Companion component below:
     <window.QueueOperationButton ... /> — wraps the queue + display
     loop, so any feature can use the pattern in 5 lines.
   ═══════════════════════════════════════════════════════════════════ */

(function () {
  'use strict';
  const { useState, useEffect, useRef, useCallback } = React;

  const RAILWAY = (window.WPSBD && window.WPSBD.railwayUrl)
    || 'https://wpsitebeam-railway-api-production.up.railway.app';

  function getToken() {
    if (window.WPSB && window.WPSB.getToken) return window.WPSB.getToken();
    return window.currentToken || '';
  }

  /* Status → visual config. Matches the operations_ui_comparison mockup. */
  const STATUS_CONFIG = {
    pending: {
      icon: 'ti-clock',
      label: 'Queued',
      bg: 'rgba(245, 158, 11, 0.12)',
      fg: 'var(--warn, #f59e0b)',
      detail: 'Plugin will pick this up within 2 min',
    },
    in_progress: {
      icon: 'ti-loader-2',
      label: 'Running',
      bg: 'rgba(59, 130, 246, 0.12)',
      fg: 'var(--beam, #3b82f6)',
      detail: 'Plugin is executing now',
      spin: true,
    },
    completed: {
      icon: 'ti-check',
      label: 'Done',
      bg: 'rgba(16, 185, 129, 0.12)',
      fg: 'var(--green, #10b981)',
      detail: '',
    },
    failed: {
      icon: 'ti-x',
      label: 'Failed',
      bg: 'rgba(239, 68, 68, 0.12)',
      fg: 'var(--red, #ef4444)',
      detail: '',
    },
    cancelled: {
      icon: 'ti-ban',
      label: 'Cancelled',
      bg: 'rgba(100, 116, 139, 0.12)',
      fg: 'var(--dim, #64748b)',
      detail: '',
    },
    expired: {
      icon: 'ti-clock-off',
      label: 'Expired',
      bg: 'rgba(100, 116, 139, 0.12)',
      fg: 'var(--dim, #64748b)',
      detail: 'Plugin never picked this up — check plugin auth',
    },
  };

  const TERMINAL_STATES = ['completed', 'failed', 'cancelled', 'expired'];

  function OperationStatusPill({ operationId, pollInterval = 4000, onComplete, compact = false }) {
    const [op, setOp] = useState(null);
    const [error, setError] = useState(null);
    const onCompleteFiredRef = useRef(false);
    const timerRef = useRef(null);

    const poll = useCallback(async () => {
      try {
        const token = getToken();
        if (!token) { setError('Not authenticated'); return; }
        const r = await fetch(`${RAILWAY}/sa/plugin/operations?limit=1&operation_id=${encodeURIComponent(operationId)}`, {
          headers: { 'Authorization': `Bearer ${token}` },
        });
        if (!r.ok) {
          if (r.status === 404) setError('Operation not found');
          else if (r.status === 503) setError('Plugin DB not migrated yet');
          else setError(`HTTP ${r.status}`);
          return;
        }
        const data = await r.json();
        /* Server's list endpoint doesn't filter by ID — we filter here.
           Better long-term: add GET /sa/plugin/operations/:id endpoint
           (queued for next session). */
        const found = (data.operations || []).find(o => o.id === operationId);
        if (!found) { setError('Operation not in list'); return; }
        setOp(found);
        setError(null);
        if (TERMINAL_STATES.includes(found.status) && !onCompleteFiredRef.current) {
          onCompleteFiredRef.current = true;
          if (onComplete) onComplete(found);
        }
      } catch (e) {
        setError(e.message);
      }
    }, [operationId, onComplete]);

    useEffect(() => {
      if (!operationId) return;
      poll(); /* immediate first fetch */
      timerRef.current = setInterval(() => {
        if (op && TERMINAL_STATES.includes(op.status)) {
          clearInterval(timerRef.current);
          return;
        }
        poll();
      }, op && op.status === 'in_progress' ? 1500 : pollInterval);
      return () => clearInterval(timerRef.current);
    }, [operationId, op && op.status, poll, pollInterval]);

    if (error) {
      return React.createElement('span', {
        style: {
          display: 'inline-flex', alignItems: 'center', gap: 4,
          padding: '3px 8px', borderRadius: 4,
          background: 'rgba(239, 68, 68, 0.12)', color: 'var(--red, #ef4444)',
          fontSize: '11px', fontWeight: 500,
        },
        title: error,
      },
        React.createElement('i', { className: 'ti ti-alert-circle', style: { fontSize: 11 }, 'aria-hidden': 'true' }),
        ' Error');
    }

    if (!op) {
      return React.createElement('span', {
        style: {
          display: 'inline-flex', alignItems: 'center', gap: 4,
          padding: '3px 8px', borderRadius: 4,
          background: 'var(--surface-2, rgba(255,255,255,0.04))', color: 'var(--dim, #64748b)',
          fontSize: '11px', fontWeight: 500,
        },
      }, 'Checking…');
    }

    const cfg = STATUS_CONFIG[op.status] || STATUS_CONFIG.pending;
    const tooltip = [
      `Type: ${op.operation_type}`,
      op.site_url ? `Site: ${op.site_url}` : null,
      op.attempts > 0 ? `Attempts: ${op.attempts}/${op.max_attempts}` : null,
      cfg.detail || null,
      op.result && op.result.items_processed != null ? `Processed: ${op.result.items_processed}` : null,
      op.result && op.result.items_failed > 0 ? `Failed: ${op.result.items_failed}` : null,
    ].filter(Boolean).join(' · ');

    const elements = [
      React.createElement('i', {
        key: 'icon',
        className: `ti ${cfg.icon}${cfg.spin ? ' wpsb-spin' : ''}`,
        style: { fontSize: 11 },
        'aria-hidden': 'true',
      }),
      ' ',
      cfg.label,
    ];
    if (!compact && op.status === 'in_progress' && op.result && op.result.items_processed != null) {
      elements.push(' · ', `${op.result.items_processed}`);
    }

    return React.createElement('span', {
      style: {
        display: 'inline-flex', alignItems: 'center', gap: 4,
        padding: '3px 8px', borderRadius: 4,
        background: cfg.bg, color: cfg.fg,
        fontSize: '11px', fontWeight: 500,
      },
      title: tooltip,
    }, ...elements);
  }

  /* ─────────────────────────────────────────────────────────────────
     QueueOperationButton — wraps the queue + status display loop.
     Drop-in for any feature that wants the standard pattern.

     Usage:
       <window.QueueOperationButton
         operationType="redirects_import"
         payload={{ rules: [...], engine: 'auto' }}
         siteUrl="https://kpchc.org"
         label="Apply 42 redirects to WP"
         onQueued={(opId) => console.log('queued', opId)}
         onComplete={(op) => refreshUi()}
       />
     ───────────────────────────────────────────────────────────────── */
  function QueueOperationButton({ operationType, payload, siteUrl, label, disabled, onQueued, onComplete }) {
    const [operationId, setOperationId] = useState(null);
    const [queuing, setQueuing] = useState(false);
    const [error, setError] = useState(null);

    const queue = async () => {
      setQueuing(true); setError(null);
      try {
        const token = getToken();
        const r = await fetch(`${RAILWAY}/sa/plugin/operations`, {
          method: 'POST',
          headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
          body: JSON.stringify({ operation_type: operationType, payload, site_url: siteUrl }),
        });
        const data = await r.json();
        if (!r.ok) {
          throw new Error(data.error || `HTTP ${r.status}`);
        }
        setOperationId(data.operation_id);
        if (onQueued) onQueued(data.operation_id);
      } catch (e) {
        setError(e.message);
        if (window.wpsbToast) window.wpsbToast(`Queue failed: ${e.message}`, 'error');
      } finally {
        setQueuing(false);
      }
    };

    const handleComplete = useCallback((finalOp) => {
      if (onComplete) onComplete(finalOp);
      if (window.wpsbToast) {
        if (finalOp.status === 'completed') {
          const items = finalOp.result?.items_processed || 0;
          window.wpsbToast(`Applied ${items} ${operationType.replace('_', ' ')} to WP`, 'ok');
        } else if (finalOp.status === 'failed') {
          window.wpsbToast(`${operationType} failed — check operations log`, 'error');
        }
      }
    }, [operationType, onComplete]);

    return React.createElement('div', { style: { display: 'inline-flex', alignItems: 'center', gap: 8 } },
      operationId
        ? React.createElement(OperationStatusPill, { operationId, onComplete: handleComplete })
        : null,
      React.createElement('button', {
        onClick: queue,
        disabled: queuing || disabled || !!operationId,
        style: {
          padding: '6px 14px', borderRadius: 6, fontSize: '13px', fontWeight: 600,
          cursor: (queuing || disabled || operationId) ? 'default' : 'pointer',
          background: (queuing || disabled || operationId) ? 'var(--surface)' : 'var(--beam, #00c2d1)',
          color: (queuing || disabled || operationId) ? 'var(--dim)' : '#000',
          border: '1px solid ' + ((queuing || disabled || operationId) ? 'var(--border)' : 'var(--beam, #00c2d1)'),
        },
      },
        queuing ? '⏳ Queueing…' : (operationId ? 'Queued' : label || 'Apply to WP')
      ),
      error ? React.createElement('span', { style: { color: 'var(--red)', fontSize: '12px' } }, error) : null,
    );
  }

  /* Inject keyframe for the loader-2 spin animation. Once globally. */
  if (!document.getElementById('wpsb-spin-keyframes')) {
    const style = document.createElement('style');
    style.id = 'wpsb-spin-keyframes';
    style.textContent = '@keyframes wpsb-spin{from{transform:rotate(0)}to{transform:rotate(360deg)}}.wpsb-spin{display:inline-block;animation:wpsb-spin 1s linear infinite}';
    document.head.appendChild(style);
  }

  window.OperationStatusPill   = OperationStatusPill;
  window.QueueOperationButton  = QueueOperationButton;
  console.log('[WPSB] OperationStatusPill + QueueOperationButton loaded');
})();
