/* ═══════════════════════════════════════════════════════════════════
   OperationsAdmin.jsx — SA Operations Tab (Option A)
   Session: 2026-05-18, fifteenth pass
   ═══════════════════════════════════════════════════════════════════
   Central view of plugin write-back operations queue. Companion to
   Option B (per-feature inline pills); used for SA diagnostics, audit,
   multi-site overview, "why did that fail last week" questions.

   Visible to: super_admin, dev_admin, internal_partner, admin, support
   Route key:  'operations' (registered in App.jsx)

   Features:
     - Filter chips by status (all/pending/in_progress/completed/failed/cancelled/expired)
     - Filter dropdown by operation_type
     - Auto-refresh every 10 seconds (toggleable)
     - Cancel pending operations
     - Click row → detail drawer with full payload + result JSON
     - Pagination (50 per page, has_more indicator)
   ═══════════════════════════════════════════════════════════════════ */

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

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

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

  async function apiGet(path) {
    const token = getToken();
    if (!token) {
      console.warn('[OperationsAdmin] No token found in window.WPSB.getToken() or window.currentToken');
      throw new Error('AUTH_NO_TOKEN — log out and back in');
    }
    const r = await fetch(`${RAILWAY}${path}`, { headers: { 'Authorization': `Bearer ${token}` } });
    const data = await r.json().catch(() => ({}));
    if (!r.ok) {
      console.warn(`[OperationsAdmin] ${path} → ${r.status}`, data);
      const codeStr = data.code ? ` (${data.code})` : '';
      const detailStr = data.error || data.detail || '';
      throw new Error(`HTTP ${r.status}${codeStr}: ${detailStr}`);
    }
    return data;
  }
  async function apiDelete(path) {
    const token = getToken();
    if (!token) throw new Error('AUTH_NO_TOKEN — log out and back in');
    const r = await fetch(`${RAILWAY}${path}`, {
      method: 'DELETE',
      headers: { 'Authorization': `Bearer ${token}` },
    });
    const data = await r.json().catch(() => ({}));
    if (!r.ok) {
      console.warn(`[OperationsAdmin] DELETE ${path} → ${r.status}`, data);
      throw new Error(data.error || `HTTP ${r.status}`);
    }
    return data;
  }

  /* Status → visual config. Matches OperationStatusPill so the central
     tab feels consistent with the inline pills. */
  const STATUS_CONFIG = {
    pending:     { icon: 'ti-clock',       label: 'Pending',     fg: 'var(--warn)',  bg: 'rgba(245,158,11,.12)' },
    in_progress: { icon: 'ti-loader-2',    label: 'Running',     fg: 'var(--beam)',  bg: 'rgba(0,194,209,.12)', spin: true },
    completed:   { icon: 'ti-check',       label: 'Completed',   fg: 'var(--green)', bg: 'rgba(16,185,129,.12)' },
    failed:      { icon: 'ti-x',           label: 'Failed',      fg: 'var(--red)',   bg: 'rgba(239,68,68,.12)' },
    cancelled:   { icon: 'ti-ban',         label: 'Cancelled',   fg: 'var(--dim)',   bg: 'rgba(100,116,139,.12)' },
    expired:     { icon: 'ti-clock-off',   label: 'Expired',     fg: 'var(--dim)',   bg: 'rgba(100,116,139,.12)' },
  };

  const TYPE_LABELS = {
    redirects_import:    { icon: 'ti-arrow-fork', label: 'Redirects' },
    alt_text_apply:      { icon: 'ti-photo',      label: 'Alt text' },
    elementor_kit_apply: { icon: 'ti-palette',    label: 'Elementor kit' },
    content_migrate:     { icon: 'ti-file-import', label: 'Content migrate' },
  };

  function StatusPill({ status, compact }) {
    const cfg = STATUS_CONFIG[status] || STATUS_CONFIG.pending;
    return React.createElement('span', {
      style: {
        display: 'inline-flex', alignItems: 'center', gap: 4,
        padding: compact ? '2px 6px' : '3px 9px', borderRadius: 4,
        background: cfg.bg, color: cfg.fg,
        fontSize: compact ? '10px' : '11px', fontWeight: 500,
        whiteSpace: 'nowrap',
      },
    },
      React.createElement('i', { className: `ti ${cfg.icon}${cfg.spin ? ' wpsb-spin' : ''}`, style: { fontSize: compact ? 10 : 11 }, 'aria-hidden': 'true' }),
      ' ', cfg.label
    );
  }

  function relTime(iso) {
    if (!iso) return '—';
    const now = Date.now();
    const then = new Date(iso).getTime();
    const sec = Math.floor((now - then) / 1000);
    if (sec < 60) return `${sec}s ago`;
    if (sec < 3600) return `${Math.floor(sec / 60)}m ago`;
    if (sec < 86400) return `${Math.floor(sec / 3600)}h ago`;
    return `${Math.floor(sec / 86400)}d ago`;
  }

  /* ── Detail drawer ──────────────────────────────────────────────── */
  function DetailDrawer({ operation, onClose, onAction }) {
    const [cancelling, setCancelling] = useState(false);
    const cancel = async () => {
      if (!window.confirm('Cancel this pending operation?')) return;
      setCancelling(true);
      try {
        await apiDelete(`/sa/plugin/operations/${operation.id}`);
        if (window.wpsbToast) window.wpsbToast('Operation cancelled', 'ok');
        if (onAction) onAction();
        onClose();
      } catch (e) {
        if (window.wpsbToast) window.wpsbToast(`Cancel failed: ${e.message}`, 'error');
      } finally {
        setCancelling(false);
      }
    };

    const t = TYPE_LABELS[operation.operation_type] || { icon: 'ti-help', label: operation.operation_type };
    const canCancel = operation.status === 'pending';

    return React.createElement('div', {
      style: {
        position: 'fixed', top: 0, right: 0, bottom: 0, width: 'min(560px, 100vw)',
        background: 'var(--surface, #111827)', borderLeft: '1px solid var(--border)',
        padding: 24, overflowY: 'auto', zIndex: 100,
        boxShadow: '-4px 0 24px rgba(0,0,0,.3)',
      },
    },
      React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 20 } },
        React.createElement('div', {},
          React.createElement('div', { style: { fontSize: '.7rem', color: 'var(--dim)', textTransform: 'uppercase', letterSpacing: '.05em', marginBottom: 4 } }, 'Operation'),
          React.createElement('div', { style: { fontSize: '1.1rem', fontWeight: 600, display: 'flex', alignItems: 'center', gap: 8 } },
            React.createElement('i', { className: `ti ${t.icon}`, style: { fontSize: 18 }, 'aria-hidden': 'true' }),
            t.label),
        ),
        React.createElement('button', { onClick: onClose, style: { background: 'none', border: 'none', color: 'var(--dim)', cursor: 'pointer', fontSize: '1.4rem' }, 'aria-label': 'Close' }, '×'),
      ),

      React.createElement('div', { style: { marginBottom: 16 } },
        React.createElement(StatusPill, { status: operation.status }),
        React.createElement('span', { style: { marginLeft: 10, fontSize: '.78rem', color: 'var(--dim)' } },
          `Attempts: ${operation.attempts}/${operation.max_attempts}`)),

      React.createElement('div', { style: { display: 'grid', gridTemplateColumns: '120px 1fr', gap: '8px 12px', fontSize: '.82rem', marginBottom: 20 } },
        React.createElement('div', { style: { color: 'var(--dim)' } }, 'ID'),
        React.createElement('div', { style: { fontFamily: 'monospace', fontSize: '.74rem', wordBreak: 'break-all' } }, operation.id),
        React.createElement('div', { style: { color: 'var(--dim)' } }, 'Site'),
        React.createElement('div', {}, operation.site_url || React.createElement('em', { style: { color: 'var(--dim)' } }, 'any site')),
        React.createElement('div', { style: { color: 'var(--dim)' } }, 'Queued'),
        React.createElement('div', {}, new Date(operation.queued_at).toLocaleString(), ' ', React.createElement('span', { style: { color: 'var(--dim)' } }, `(${relTime(operation.queued_at)})`)),
        operation.claimed_at && React.createElement('div', { style: { color: 'var(--dim)' } }, 'Claimed'),
        operation.claimed_at && React.createElement('div', {}, new Date(operation.claimed_at).toLocaleString()),
        operation.completed_at && React.createElement('div', { style: { color: 'var(--dim)' } }, 'Completed'),
        operation.completed_at && React.createElement('div', {}, new Date(operation.completed_at).toLocaleString()),
        React.createElement('div', { style: { color: 'var(--dim)' } }, 'Expires'),
        React.createElement('div', {}, new Date(operation.expires_at).toLocaleString()),
      ),

      React.createElement('div', { style: { marginBottom: 16 } },
        React.createElement('div', { style: { fontSize: '.72rem', color: 'var(--dim)', textTransform: 'uppercase', letterSpacing: '.05em', marginBottom: 6 } }, 'Payload'),
        React.createElement('pre', { style: { background: 'var(--surface-2, rgba(255,255,255,.03))', padding: 12, borderRadius: 6, fontSize: '.72rem', overflowX: 'auto', maxHeight: 240, color: 'var(--text)' } },
          JSON.stringify(operation.payload || {}, null, 2))),

      operation.result && React.createElement('div', { style: { marginBottom: 16 } },
        React.createElement('div', { style: { fontSize: '.72rem', color: 'var(--dim)', textTransform: 'uppercase', letterSpacing: '.05em', marginBottom: 6 } }, 'Result'),
        React.createElement('pre', { style: { background: 'var(--surface-2, rgba(255,255,255,.03))', padding: 12, borderRadius: 6, fontSize: '.72rem', overflowX: 'auto', maxHeight: 200, color: 'var(--text)' } },
          JSON.stringify(operation.result, null, 2))),

      canCancel && React.createElement('button', {
        onClick: cancel, disabled: cancelling,
        style: {
          padding: '8px 16px', borderRadius: 6, fontSize: '.82rem', fontWeight: 600,
          background: 'var(--red)', color: '#fff', border: '1px solid var(--red)', cursor: cancelling ? 'default' : 'pointer',
        },
      }, cancelling ? 'Cancelling…' : 'Cancel pending operation'),
    );
  }

  /* ── Main panel ─────────────────────────────────────────────────── */
  function OperationsAdmin() {
    const [ops, setOps] = useState([]);
    const [counts, setCounts] = useState({ all: 0, pending: 0, in_progress: 0, completed: 0, failed: 0, cancelled: 0, expired: 0 });
    const [statusFilter, setStatusFilter] = useState('all');
    const [typeFilter, setTypeFilter] = useState('');
    const [offset, setOffset] = useState(0);
    const [total, setTotal] = useState(0);
    const [hasMore, setHasMore] = useState(false);
    const [loading, setLoading] = useState(false);
    const [err, setErr] = useState(null);
    const [selected, setSelected] = useState(null);
    const [autoRefresh, setAutoRefresh] = useState(true);
    const timerRef = useRef(null);

    const load = useCallback(async (newOffset = 0) => {
      setLoading(true); setErr(null);
      try {
        const params = new URLSearchParams({ limit: LIMIT, offset: newOffset });
        if (statusFilter !== 'all') params.set('status', statusFilter);
        if (typeFilter)             params.set('operation_type', typeFilter);
        const data = await apiGet(`/sa/plugin/operations?${params}`);
        setOps(data.operations || []);
        setTotal(data.total || 0);
        setHasMore(data.has_more || false);
        setOffset(newOffset);

        /* Refresh counts — one extra call with no status filter */
        if (statusFilter === 'all' && newOffset === 0 && !typeFilter) {
          const all = await apiGet(`/sa/plugin/operations?limit=200&offset=0`);
          const c = { all: all.total, pending: 0, in_progress: 0, completed: 0, failed: 0, cancelled: 0, expired: 0 };
          (all.operations || []).forEach(o => { if (c[o.status] !== undefined) c[o.status]++; });
          setCounts(c);
        }
      } catch (e) {
        setErr(e.message);
      } finally {
        setLoading(false);
      }
    }, [statusFilter, typeFilter]);

    useEffect(() => { load(0); }, [statusFilter, typeFilter]);

    /* Auto-refresh every 10s if enabled. Pauses while detail drawer is open. */
    useEffect(() => {
      if (!autoRefresh || selected) {
        if (timerRef.current) clearInterval(timerRef.current);
        return;
      }
      timerRef.current = setInterval(() => load(offset), 10000);
      return () => clearInterval(timerRef.current);
    }, [autoRefresh, selected, load, offset]);

    const chip = (key, label, count) => React.createElement('button', {
      key,
      onClick: () => { setStatusFilter(key); setOffset(0); },
      style: {
        padding: '5px 11px', borderRadius: 6, fontSize: '.78rem', fontWeight: 500,
        cursor: 'pointer',
        background: statusFilter === key ? 'var(--surface-2)' : 'transparent',
        color: statusFilter === key ? 'var(--text)' : 'var(--dim)',
        border: '1px solid ' + (statusFilter === key ? 'var(--border-2, var(--border))' : 'var(--border)'),
      },
    }, label, ' · ', count);

    /* Width fix 2026-05-20 — removed `padding: '20px 24px', maxWidth: 1280` to
       match Brand Profile / Account / Billing / AIUsage standard width.
       The .main grid container in shell.css handles overall width + padding. */
    return React.createElement('div', null,
      /* Header */
      React.createElement('div', { style: { display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 4 } },
        React.createElement('h1', { style: { fontSize: '1.4rem', fontWeight: 700, margin: 0 } }, 'Operations queue'),
        React.createElement('label', { style: { fontSize: '.78rem', color: 'var(--dim)', display: 'flex', alignItems: 'center', gap: 6 } },
          React.createElement('input', { type: 'checkbox', checked: autoRefresh, onChange: e => setAutoRefresh(e.target.checked) }),
          'Auto-refresh (10s)')),
      React.createElement('p', { style: { fontSize: '.85rem', color: 'var(--dim)', margin: '4px 0 18px' } },
        'Plugin write-back queue across all accounts. Use ',
        React.createElement('em', {}, 'Cancel'),
        ' to drop a pending operation before the plugin picks it up.'),

      /* Filter chips */
      React.createElement('div', { style: { display: 'flex', gap: 6, marginBottom: 12, flexWrap: 'wrap', alignItems: 'center' } },
        chip('all',         'All',         counts.all),
        chip('pending',     'Pending',     counts.pending),
        chip('in_progress', 'In progress', counts.in_progress),
        chip('completed',   'Completed',   counts.completed),
        chip('failed',      'Failed',      counts.failed),
        chip('cancelled',   'Cancelled',   counts.cancelled),
        chip('expired',     'Expired',     counts.expired),

        React.createElement('div', { style: { flex: 1 } }),

        React.createElement('select', {
          value: typeFilter,
          onChange: e => { setTypeFilter(e.target.value); setOffset(0); },
          style: {
            padding: '5px 10px', borderRadius: 6, fontSize: '.78rem',
            background: 'var(--surface-2)', color: 'var(--text)', border: '1px solid var(--border)',
          },
        },
          React.createElement('option', { value: '' }, 'All types'),
          Object.keys(TYPE_LABELS).map(t => React.createElement('option', { key: t, value: t }, TYPE_LABELS[t].label)),
        ),
      ),

      /* Table */
      err && React.createElement('div', { style: { padding: 12, background: 'rgba(239,68,68,.1)', color: 'var(--red)', borderRadius: 6, marginBottom: 12, fontSize: '.82rem' } },
        err.includes('MIGRATION_PENDING') || err.includes('not migrated')
          ? React.createElement('span', {}, '⚠️ Plugin write-back DB not migrated yet. Run ', React.createElement('code', {}, '_PLUGIN-WRITEBACK-MIGRATION.sql'), ' in Supabase first.')
          : err
      ),

      ops.length === 0 && !loading && !err && React.createElement('div', { style: { padding: 40, textAlign: 'center', color: 'var(--dim)', fontSize: '.85rem' } },
        statusFilter === 'all' && !typeFilter
          ? 'No operations yet. Queue one from any feature page (Redirects, Alt Text, Site Builder Theme).'
          : `No operations match the current filters.`),

      ops.length > 0 && React.createElement('div', { style: { background: 'var(--surface, #111827)', border: '1px solid var(--border)', borderRadius: 8, overflow: 'hidden' } },
        /* Header row */
        React.createElement('div', { style: { display: 'grid', gridTemplateColumns: '24px 1.4fr 1fr 0.8fr 0.7fr 110px 60px', gap: 10, padding: '10px 14px', fontSize: '.68rem', color: 'var(--dim)', textTransform: 'uppercase', letterSpacing: '.05em', background: 'var(--surface-2)', borderBottom: '1px solid var(--border)' } },
          React.createElement('span', {}),
          React.createElement('span', {}, 'Type · Detail'),
          React.createElement('span', {}, 'Site'),
          React.createElement('span', {}, 'Queued'),
          React.createElement('span', {}, 'Attempts'),
          React.createElement('span', { style: { textAlign: 'right' } }, 'Status'),
          React.createElement('span', { style: { textAlign: 'right' } }, ''),
        ),

        /* Operation rows */
        ops.map(op => {
          const t = TYPE_LABELS[op.operation_type] || { icon: 'ti-help', label: op.operation_type };
          const detail = op.payload?.rules ? `${op.payload.rules.length} rules`
                       : op.payload?.items ? `${op.payload.items.length} items`
                       : '';
          return React.createElement('div', {
            key: op.id,
            onClick: () => setSelected(op),
            style: {
              display: 'grid', gridTemplateColumns: '24px 1.4fr 1fr 0.8fr 0.7fr 110px 60px', gap: 10,
              padding: '10px 14px', fontSize: '.85rem', borderBottom: '1px solid var(--border)',
              cursor: 'pointer', alignItems: 'center',
              transition: 'background .12s',
            },
            onMouseOver: e => e.currentTarget.style.background = 'var(--surface-2)',
            onMouseOut:  e => e.currentTarget.style.background = 'transparent',
          },
            React.createElement('i', { className: `ti ${t.icon}`, style: { fontSize: 16, color: 'var(--dim)' }, 'aria-hidden': 'true' }),
            React.createElement('span', {},
              t.label,
              detail ? React.createElement('span', { style: { color: 'var(--dim)', marginLeft: 6, fontSize: '.78rem' } }, ' · ' + detail) : null),
            React.createElement('span', { style: { color: 'var(--dim)', fontSize: '.78rem', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, op.site_url || '—'),
            React.createElement('span', { style: { color: 'var(--dim)', fontSize: '.78rem' } }, relTime(op.queued_at)),
            React.createElement('span', { style: { color: op.attempts > 0 ? 'var(--warn)' : 'var(--dim)', fontSize: '.78rem' } },
              op.attempts > 0 ? `${op.attempts}/${op.max_attempts}` : '—'),
            React.createElement('span', { style: { textAlign: 'right' } }, React.createElement(StatusPill, { status: op.status })),
            React.createElement('span', { style: { textAlign: 'right', color: 'var(--dim)' } }, '›'),
          );
        }),
      ),

      /* Pagination */
      ops.length > 0 && (offset > 0 || hasMore) && React.createElement('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginTop: 12, fontSize: '.78rem', color: 'var(--dim)' } },
        React.createElement('span', {}, `Showing ${offset + 1}–${offset + ops.length} of ${total}`),
        React.createElement('div', { style: { display: 'flex', gap: 6 } },
          React.createElement('button', {
            disabled: offset === 0,
            onClick: () => load(Math.max(0, offset - LIMIT)),
            style: {
              padding: '4px 10px', borderRadius: 4, fontSize: '.78rem',
              background: 'var(--surface-2)', border: '1px solid var(--border)',
              color: offset === 0 ? 'var(--dim)' : 'var(--text)',
              cursor: offset === 0 ? 'default' : 'pointer',
            },
          }, '← Previous'),
          React.createElement('button', {
            disabled: !hasMore,
            onClick: () => load(offset + LIMIT),
            style: {
              padding: '4px 10px', borderRadius: 4, fontSize: '.78rem',
              background: 'var(--surface-2)', border: '1px solid var(--border)',
              color: !hasMore ? 'var(--dim)' : 'var(--text)',
              cursor: !hasMore ? 'default' : 'pointer',
            },
          }, 'Next →'),
        ),
      ),

      /* Detail drawer */
      selected && React.createElement(DetailDrawer, {
        operation: selected,
        onClose: () => setSelected(null),
        onAction: () => load(offset),
      }),
    );
  }

  window.OperationsAdmin = OperationsAdmin;
  console.log('[WPSB] OperationsAdmin loaded');
})();
