// T2 Falcon Admin — Applications table (Apps & Services / Comm Channels tabs)

const { useState: useStateA, useRef: useRefA, useEffect: useEffectA, useMemo: useMemoA } = React;

// ===== Header label helper: break into 2-words-per-line =====
const wrapTwo = (label) => {
  if (!label) return null;
  const words = label.split(/\s+/);
  const lines = [];
  for (let i = 0; i < words.length; i += 2) lines.push(words.slice(i, i + 2).join(' '));
  return lines.map((line, i) => (
    <React.Fragment key={i}>
      {i > 0 && <br />}
      {line}
    </React.Fragment>
  ));
};


// ===== Seed apps per tab =====
const APPS_BY_TAB = {
  appsServices: [
  { id: 'a1', name: 'Basic Send App', priceType: 'Monthly', priceValue: 2000, firstActivation: '1/1/2025', activation: '1/1/2025', renew: '1/1/2026', status: 'active', visible: true },
  { id: 'a2', name: 'Survey Pro', priceType: 'Monthly', priceValue: 2000, firstActivation: '1/1/2025', activation: '1/1/2025', renew: '1/1/2026', status: 'active', visible: true },
  { id: 'a3', name: 'Campaign Engine', priceType: 'Yearly', priceValue: 18000, firstActivation: '3/15/2023', activation: '3/15/2024', renew: '3/15/2025', status: 'expired', visible: true },
  { id: 'a4', name: 'Workflow Builder', priceType: 'Quarterly', priceValue: 5500, firstActivation: '2/1/2024', activation: '2/1/2025', renew: '5/1/2025', status: 'expired', visible: true },
  { id: 'a5', name: 'Analytics Suite', priceType: 'Monthly', priceValue: 3500, firstActivation: '6/10/2024', activation: '6/10/2025', renew: '7/10/2025', status: 'disable', visible: true },
  { id: 'a6', name: 'Form Builder', priceType: 'Yearly', priceValue: 12000, firstActivation: '4/1/2024', activation: '4/1/2025', renew: '4/1/2026', status: 'disable', visible: false },
  { id: 'a7', name: 'Reporting Hub', priceType: 'Monthly', priceValue: 2800, firstActivation: '8/1/2024', activation: '8/1/2025', renew: '9/1/2025', status: 'inactive', visible: true },
  { id: 'a8', name: 'AI Assistant', priceType: 'Monthly', priceValue: 4200, firstActivation: null, activation: null, renew: null, status: 'inactive', visible: false }],

  commChannels: [
  { id: 'c1', name: 'SMS Gateway', priceType: 'Monthly', priceValue: 4500, firstActivation: '2/1/2024', purchaseDate: '1/15/2024', activation: '2/1/2025', renew: '2/1/2026', status: 'active', visible: true },
  { id: 'c2', name: 'WhatsApp Business', priceType: 'Monthly', priceValue: 3200, firstActivation: null, purchaseDate: '6/1/2024', activation: '6/1/2024', renew: null, status: 'paid', visible: true },
  { id: 'c3', name: 'Email Relay', priceType: 'Yearly', priceValue: 8400, firstActivation: '1/1/2024', purchaseDate: '12/15/2023', activation: '1/1/2025', renew: '1/1/2026', status: 'active', visible: true },
  { id: 'c4', name: 'Voice IVR', priceType: 'Monthly', priceValue: 7800, firstActivation: null, purchaseDate: '4/20/2024', activation: '4/20/2024', renew: null, status: 'paid', visible: true },
  { id: 'c5', name: 'Push Notifications', priceType: 'Yearly', priceValue: 6000, firstActivation: '3/1/2023', purchaseDate: '2/20/2023', activation: '3/1/2024', renew: '3/1/2025', status: 'expired', visible: true },
  { id: 'c6', name: 'AI-ChatGPT', priceType: 'Monthly', priceValue: 5200, firstActivation: '7/1/2024', purchaseDate: '6/20/2024', activation: '7/1/2025', renew: '9/1/2025', status: 'active', visible: true },
  { id: 'c7', name: 'RCS Messaging', priceType: 'Quarterly', priceValue: 4800, firstActivation: '2/15/2024', purchaseDate: '2/1/2024', activation: '2/15/2025', renew: '5/15/2025', status: 'expired', visible: true },
  { id: 'c8', name: 'Telegram Bot', priceType: 'Monthly', priceValue: 2600, firstActivation: '9/1/2024', purchaseDate: '8/20/2024', activation: '9/1/2025', renew: '10/1/2025', status: 'inactive', visible: true },
  { id: 'c9', name: 'Apple Business Chat', priceType: 'Monthly', priceValue: 3600, firstActivation: null, purchaseDate: null, activation: null, renew: null, status: 'inactive', visible: false }]

};

// ===== Visibility toggle =====
const VisibilityToggle = ({ on, onChange, disabled = false, title }) =>
<button
  type="button"
  role="switch"
  aria-checked={on}
  disabled={disabled}
  title={title}
  className={`vis-toggle ${on ? 'on' : ''} ${disabled ? 'is-locked' : ''}`}
  onClick={() => { if (!disabled) onChange(!on); }}>

    <span className="vis-toggle-dot" />
  </button>;


// ===== Currency symbol (Saudi Riyal — official 2025 glyph) =====
const SAR = ({ size = 12 }) => <IcRiyal size={size} />;


// ===== Date picker (with disabled past dates) =====
const MONTH_NAMES = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
const WEEK_DAYS = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];

const parseMdy = (s) => {
  if (!s || s === '—') return null;
  const [m, d, y] = s.split('/').map(Number);
  return new Date(y, m - 1, d);
};
const formatMdy = (d) => `${d.getMonth() + 1}/${d.getDate()}/${d.getFullYear()}`;
// System-wide display format: DD-Mon-YYYY (e.g. 27-Mar-2025). Accepts a Date or an M/D/YYYY string;
// passes anything else (null, already-formatted) straight through.
const DMY_MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
const formatDMY = (v) => {
  if (!v) return v;
  let dt;
  if (v instanceof Date) dt = v;
  else {
    const m = String(v).match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);
    if (!m) return v;
    dt = new Date(Number(m[3]), Number(m[1]) - 1, Number(m[2]));
  }
  return `${String(dt.getDate()).padStart(2, '0')}-${DMY_MONTHS[dt.getMonth()]}-${dt.getFullYear()}`;
};
window.formatDMY = formatDMY;
const sameDay = (a, b) => a && b && a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
const startOfDay = (d) => {const x = new Date(d);x.setHours(0, 0, 0, 0);return x;};

const DatePicker = ({ value, onChange, minDate }) => {
  const [open, setOpen] = useStateA(false);
  const [up, setUp] = useStateA(false);   // flip above the field when there isn't room below
  const [view, setView] = useStateA(() => value ? new Date(value) : new Date());
  const ref = useRefA(null);

  useEffectA(() => {
    if (!open) return;
    const onDoc = (e) => {if (ref.current && !ref.current.contains(e.target)) setOpen(false);};
    document.addEventListener('mousedown', onDoc);
    return () => document.removeEventListener('mousedown', onDoc);
  }, [open]);
  useEffectA(() => { if (!open || !ref.current) return; const r = ref.current.getBoundingClientRect(); setUp((window.innerHeight - r.bottom) < 340); }, [open]);

  const y = view.getFullYear(),m = view.getMonth();
  const firstDow = new Date(y, m, 1).getDay();
  const daysInMonth = new Date(y, m + 1, 0).getDate();
  const today = startOfDay(new Date());
  const min = minDate ? startOfDay(minDate) : today;

  const cells = [];
  for (let i = 0; i < firstDow; i++) cells.push(null);
  for (let d = 1; d <= daysInMonth; d++) cells.push(new Date(y, m, d));
  while (cells.length % 7 !== 0) cells.push(null);

  return (
    <div className="dp-wrap" ref={ref}>
      <button
        type="button"
        className="dp-trigger"
        onClick={() => setOpen((v) => !v)}>
        
        <span>{value ? formatDMY(value) : 'dd-mmm-yyyy'}</span>
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
          <rect x="3" y="4" width="18" height="18" rx="2" />
          <line x1="16" y1="2" x2="16" y2="6" />
          <line x1="8" y1="2" x2="8" y2="6" />
          <line x1="3" y1="10" x2="21" y2="10" />
        </svg>
      </button>
      {open &&
      <div className={`dp-pop ${up ? 'up' : ''}`}>
          <div className="dp-head">
            <button type="button" className="dp-nav" onClick={() => setView(new Date(y, m - 1, 1))} aria-label="Previous month">
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="15 18 9 12 15 6" /></svg>
            </button>
            <div className="dp-title">{MONTH_NAMES[m]} {y}</div>
            <button type="button" className="dp-nav" onClick={() => setView(new Date(y, m + 1, 1))} aria-label="Next month">
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="9 18 15 12 9 6" /></svg>
            </button>
          </div>
          <div className="dp-dow">
            {WEEK_DAYS.map((d) => <span key={d}>{d}</span>)}
          </div>
          <div className="dp-grid">
            {cells.map((d, i) => {
            if (!d) return <span key={i} className="dp-cell empty" />;
            const disabled = d < min;
            const selected = sameDay(d, value);
            const isToday = sameDay(d, today);
            return (
              <button
                key={i}
                type="button"
                disabled={disabled}
                className={`dp-cell ${disabled ? 'disabled' : ''} ${selected ? 'selected' : ''} ${isToday ? 'today' : ''}`}
                onClick={() => {if (!disabled) {onChange(d);setOpen(false);}}}>
                
                  {d.getDate()}
                </button>);

          })}
          </div>
        </div>
      }
    </div>);

};

window.DatePicker = DatePicker;

// ===== Edit expansion row — mode: 'type' | 'value', uiMode: 'edit' | 'view' =====
const EditRow = ({ app, mode, uiMode, pending, onCancel, onSave, onEditAgain, onRemove, t, hideVisibility = false, isComm = false }) => {
  const initialType = pending?.priceType || app.priceType || 'Monthly';
  const initialDate = pending?.effDate ? parseMdy(pending.effDate) : (() => { const d = new Date(); d.setDate(d.getDate() + 10); return d; })();
  const initialVal = pending?.priceValue ?? app.priceValue ?? 2000;

  const [priceType, setPriceType] = useStateA(initialType);
  const [effDate, setEffDate] = useStateA(initialDate);
  const [priceValue, setPriceValue] = useStateA(initialVal);

  const handleSave = () => onSave({
    priceType: mode === 'type' ? priceType : app.priceType,
    effDate: mode === 'type' ? formatMdy(effDate) : (pending?.effDate || app.activation),
    priceValue: mode === 'value' ? priceValue : app.priceValue
  });

  const EditActions = () =>
    <div className="edit-actions">
      <button className="edit-btn cancel-btn-text" onClick={onCancel}>{t.cancel}</button>
      <button className="edit-btn save-btn-text" onClick={handleSave}>{t.save}</button>
    </div>;

  const ViewActions = () =>
    <div className="edit-actions">
      <button className="edit-icon-btn view-edit-btn" onClick={onEditAgain} title={t.edit} aria-label={t.edit}>
        <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
          <rect x="3" y="5" width="18" height="14" rx="2" />
          <line x1="3" y1="10" x2="21" y2="10" />
          <path d="m16 14 3 3-3 3" />
          <path d="M19 17h-7" />
        </svg>
      </button>
      <button className="edit-icon-btn view-remove-btn" onClick={onRemove} title={t.delete} aria-label={t.delete}>
        <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
          <polyline points="3 6 5 6 21 6" />
          <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6" />
          <path d="M10 11v6M14 11v6" />
          <path d="M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2" />
        </svg>
      </button>
    </div>;

  if (mode === 'type') {
    return (
      <tr className={`edit-expand-row edit-row-top ${uiMode === 'view' ? 'view-row' : ''}`}>
        {!hideVisibility && <td></td>}
        <td></td>
        <td className="edit-cell-pointer">
          <div className="edit-field">
            <span className="edit-field-label">{t.newPriceType}</span>
            {uiMode === 'edit' ?
              <div className="edit-pill">
                <select className="edit-select-pill" value={priceType} onChange={(e) => setPriceType(e.target.value)}>
                  <option value="OneTime">{t.priceOneTime}</option>
                  <option value="Monthly">{t.priceMonthly}</option>
                  <option value="Quarterly">{t.priceQuarterly}</option>
                  <option value="Yearly">{t.priceYearly}</option>
                </select>
              </div>
              :
              <div className="view-value">{priceType === 'OneTime' ? t.priceOneTime : priceType === 'Monthly' ? t.priceMonthly : priceType === 'Quarterly' ? t.priceQuarterly : t.priceYearly}</div>
            }
          </div>
        </td>
        <td colSpan="2">
          <div className="edit-field">
            <span className="edit-field-label">{t.effectiveDate}</span>
            {uiMode === 'edit' ?
              <div className="edit-pill"><DatePicker value={effDate} onChange={setEffDate} /></div>
              :
              <div className="view-value">{formatDMY(effDate)}</div>
            }
          </div>
        </td>
        {isComm && <td></td>}
        <td></td>
        <td></td>
        <td></td>
        <td className="edit-actions-cell">{uiMode === 'edit' ? <EditActions /> : <ViewActions />}</td>
      </tr>);
  }

  // value mode
  return (
    <tr className={`edit-expand-row edit-row-top edit-row-bot ${uiMode === 'view' ? 'view-row' : ''}`}>
      {!hideVisibility && <td></td>}
      <td></td>
      <td></td>
      <td className="edit-cell-pointer" colSpan="2">
        <div className="edit-field">
          <span className="edit-field-label">{t.newPriceValue}</span>
          {uiMode === 'edit' ?
            <div className="edit-pill">
              <div className="edit-price-input">
                <SAR />
                <input
                  type="number"
                  value={priceValue}
                  onChange={(e) => setPriceValue(Number(e.target.value) || 0)}
                  className="edit-input" />
              </div>
            </div>
            :
            <div className="view-value"><SAR /> <strong>{priceValue.toLocaleString()}</strong></div>
          }
        </div>
      </td>
      {isComm && <td></td>}
      <td></td>
      <td></td>
      <td></td>
      <td className="edit-actions-cell">{uiMode === 'edit' ? <EditActions /> : <ViewActions />}</td>
    </tr>);

};

// ===== Insufficient Balance modal (Drag to change priority) =====
const InsufficientBalanceModal = ({ onCancel, onProceed, t }) => {
  const [items, setItems] = useStateA([
    { id: 'wa', name: 'WhatsApp' },
    { id: 'voice', name: 'Voice' },
    { id: 'gpt', name: 'AI-ChatGPT' }]);
  const [draggingIdx, setDraggingIdx] = useStateA(null);
  const [overIdx, setOverIdx] = useStateA(null);

  const move = (from, to) => {
    if (to < 0 || to >= items.length) return;
    const next = [...items];
    const [moved] = next.splice(from, 1);
    next.splice(to, 0, moved);
    setItems(next);
  };

  const onDragStart = (i) => (e) => {
    setDraggingIdx(i);
    e.dataTransfer.effectAllowed = 'move';
    try { e.dataTransfer.setData('text/plain', String(i)); } catch (_) {}
  };
  const onDragOver = (i) => (e) => { e.preventDefault(); setOverIdx(i); };
  const onDrop = (i) => (e) => {
    e.preventDefault();
    if (draggingIdx == null || draggingIdx === i) { setDraggingIdx(null); setOverIdx(null); return; }
    move(draggingIdx, i);
    setDraggingIdx(null);
    setOverIdx(null);
  };
  const onDragEnd = () => { setDraggingIdx(null); setOverIdx(null); };

  return (
    <div className="ib-overlay" onClick={onCancel}>
      <div className="ib-modal" onClick={(e) => e.stopPropagation()}>
        <div className="ib-icon-wrap">
          <svg viewBox="0 0 64 64" width="56" height="56" fill="none">
            <path d="M32 6 L60 56 L4 56 Z" fill="#E63946" />
            <rect x="30" y="22" width="4" height="18" rx="2" fill="white" />
            <circle cx="32" cy="48" r="2.4" fill="white" />
          </svg>
        </div>
        <div className="ib-title">{t.ibTitle}</div>
        <div className="ib-subtitle">{t.ibSubtitle}</div>

        <div className="ib-card">
          <div className="ib-drag-label">{t.ibDragLabel}</div>
          <div className="ib-list">
            {items.map((it, i) =>
              <div key={it.id} className="ib-row">
                <div className="ib-rank">{i + 1}</div>
                <div
                  className={`ib-item ${draggingIdx === i ? 'dragging' : ''} ${overIdx === i && draggingIdx !== i ? 'drop-target' : ''}`}
                  draggable="true"
                  onDragStart={onDragStart(i)}
                  onDragOver={onDragOver(i)}
                  onDrop={onDrop(i)}
                  onDragEnd={onDragEnd}>
                  <span className="ib-grip" aria-hidden="true">
                    <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
                      <circle cx="9" cy="6" r="1.4" /><circle cx="15" cy="6" r="1.4" />
                      <circle cx="9" cy="12" r="1.4" /><circle cx="15" cy="12" r="1.4" />
                      <circle cx="9" cy="18" r="1.4" /><circle cx="15" cy="18" r="1.4" />
                    </svg>
                  </span>
                  <span className="ib-item-name">{it.name}</span>
                  <button type="button" className="ib-arrow" onClick={() => move(i, i + 1)} aria-label="Move down" disabled={i === items.length - 1}>
                    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="6 9 12 15 18 9" /></svg>
                  </button>
                  <button type="button" className="ib-arrow" onClick={() => move(i, i - 1)} aria-label="Move up" disabled={i === 0}>
                    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="6 15 12 9 18 15" /></svg>
                  </button>
                </div>
              </div>
            )}
          </div>
        </div>

        <div className="ib-info">
          <span className="ib-info-dot">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
              <circle cx="12" cy="12" r="10" /><line x1="12" y1="16" x2="12" y2="12" /><line x1="12" y1="8" x2="12.01" y2="8" />
            </svg>
          </span>
          <span>{t.ibFirstAuto}</span>
        </div>

        <div className="ib-actions">
          <button className="ib-btn ib-btn-cancel" onClick={onCancel}>{t.ibCancel}</button>
          <button className="ib-btn ib-btn-proceed" onClick={() => onProceed(items)}>{t.ibProceed}</button>
        </div>
      </div>
    </div>);

};

// ===== Row actions menu (⋮) — items per status =====
const ActionIcons = {
  disable: () => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9" /><line x1="5.6" y1="5.6" x2="18.4" y2="18.4" /></svg>,
  enable: () => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9" /><polyline points="8 12.5 11 15.5 16 9.5" /></svg>,
  doPayment: () => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="6" width="18" height="13" rx="2" /><path d="M3 11h18" /><path d="M7 16h3" /></svg>,
  edit: () => <IcEdit size={14} stroke={1.8} />
};

const RowActionsMenu = ({ status, onAction, onClose, t, isComm = false }) => {
  const ref = useRefA(null);
  useEffectA(() => {
    const onDoc = (e) => {if (ref.current && !ref.current.contains(e.target)) onClose();};
    document.addEventListener('mousedown', onDoc);
    return () => document.removeEventListener('mousedown', onDoc);
  }, []);

  const editItems = [
    { id: 'editType', label: t.actEditPriceType, icon: ActionIcons.edit },
    { id: 'editValue', label: t.actEditPriceValue, icon: ActionIcons.edit }];

  // CommChannels: no enable/disable; "Paid" rows expose "Activate".
  let items = [];
  if (isComm) {
    if (status === 'active') {
      items = [...editItems];
    } else if (status === 'paid') {
      items = [{ id: 'activate', label: t.actActivate, icon: ActionIcons.enable }, ...editItems];
    } else if (status === 'expired') {
      items = [{ id: 'doPayment', label: t.actDoPayment, icon: ActionIcons.doPayment }, ...editItems];
    } else if (status === 'inactive') {
      items = [{ id: 'doPayment', label: t.actDoPayment, icon: ActionIcons.doPayment }];
    }
  } else if (status === 'active') {
    items = [
      { id: 'disable', label: t.actDisable, icon: ActionIcons.disable },
      ...editItems];
  } else if (status === 'expired') {
    items = [
      { id: 'doPayment', label: t.actDoPayment, icon: ActionIcons.doPayment },
      { id: 'disable', label: t.actDisable, icon: ActionIcons.disable },
      ...editItems];
  } else if (status === 'disable') {
    items = [
      { id: 'enable', label: t.actEnable, icon: ActionIcons.enable },
      ...editItems];
  } else if (status === 'inactive') {
    items = [
      { id: 'doPayment', label: t.actDoPayment, icon: ActionIcons.doPayment },
      { id: 'disable', label: t.actDisable, icon: ActionIcons.disable }];
  }

  return (
    <div className="row-actions-pop apps-actions-pop" ref={ref}>
      {items.map((it) =>
        <button key={it.id} className="row-actions-item" onClick={() => onAction(it.id)}>
          <it.icon />
          <span>{it.label}</span>
        </button>
      )}
    </div>);

};

const ApplicationsPage = ({ tabKey, t, pushToast, hideVisibility = false, nodeId = null }) => {
  const isComm = tabKey === 'commChannels';
  const hasActiveContract = useMemoA(
    () => (window.seedContracts?.[nodeId] || []).some((c) => c.status === 'active'),
    [nodeId]);
  const [visWarn, setVisWarn] = useStateA(null); // id awaiting "make visible" confirmation
  const [apps, setApps] = useStateA(() => APPS_BY_TAB[tabKey] || APPS_BY_TAB.appsServices);
  const [editingId, setEditingId] = useStateA(null);
  const [editMode, setEditMode] = useStateA(null); // 'type' | 'value'
  const [uiMode, setUiMode] = useStateA('edit'); // 'edit' | 'view'
  const [pendingMap, setPendingMap] = useStateA({}); // { id: { type: {...}, value: {...} } }
  const [expandedId, setExpandedId] = useStateA(null);
  const [menuFor, setMenuFor] = useStateA(null);
  const [showIB, setShowIB] = useStateA(false);
  const [ibTargetId, setIbTargetId] = useStateA(null);
  const [appsPage, setAppsPage] = useStateA(1);
  const [appsPageSize, setAppsPageSize] = useStateA(20);

  useEffectA(() => {
    setApps(APPS_BY_TAB[tabKey] || APPS_BY_TAB.appsServices);
    setEditingId(null);
    setEditMode(null);
    setExpandedId(null);
    setPendingMap({});
    setMenuFor(null);
    setShowIB(false);
  }, [tabKey]);

  const setVisible = (id, on) => setApps((a) => a.map((x) => x.id === id ? { ...x, visible: on } : x));
  const toggleVis = (id) => {
    const app = apps.find((x) => x.id === id);
    // Visibility is locked once a commchannel has been purchased.
    if (isComm && app && app.purchaseDate) return;
    const turningOn = app && !app.visible;
    // Warn before making a commchannel visible — only if the tenant has an active contract.
    if (isComm && turningOn && hasActiveContract) { setVisWarn(id); return; }
    setVisible(id, !(app && app.visible));
  };
  const confirmVis = () => { if (visWarn) setVisible(visWarn, true); setVisWarn(null); };

  const handleSet = (id, next) => {
    // Save the pending change but switch to view mode (don't apply to row yet)
    setPendingMap((m) => ({
      ...m,
      [id]: { ...(m[id] || {}), [editMode]: next }
    }));
    setUiMode('view');
    setEditingId(null);
    setEditMode(null);
    setExpandedId(id);
    pushToast(`${t.applications}: ${t.save} ✓`);
  };

  const handleAction = (id, action) => {
    setMenuFor(null);
    if (action === 'disable') {
      setApps((a) => a.map((x) => x.id === id ? { ...x, status: 'disable' } : x));
      pushToast(`${t.actDisable} ✓`);
    } else if (action === 'enable') {
      setApps((a) => a.map((x) => x.id === id ? { ...x, status: 'active' } : x));
      pushToast(`${t.actEnable} ✓`);
    } else if (action === 'editType') {
      setEditingId(id);
      setEditMode('type');
      setUiMode('edit');
      setExpandedId(id);
    } else if (action === 'editValue') {
      setEditingId(id);
      setEditMode('value');
      setUiMode('edit');
      setExpandedId(id);
    } else if (action === 'activate') {
      // Route by channel: WhatsApp → Meta Service .Mng; Voice (and any other) → Voice Service, Voice account tab.
      const ch = (window.CM_META && window.CM_META[id] && window.CM_META[id].icon) || '';
      if (ch === 'whatsapp') { if (window.falconGoMetaService) window.falconGoMetaService(); }
      else { if (window.falconGoVoiceAccount) window.falconGoVoiceAccount(); }
    } else if (action === 'doPayment') {
      setIbTargetId(id);
      setShowIB(true);
    }
  };

  const removePending = (id, mode) => {
    setPendingMap((m) => {
      const next = { ...m };
      if (next[id]) {
        const { [mode]: _, ...rest } = next[id];
        if (Object.keys(rest).length === 0) delete next[id];
        else next[id] = rest;
      }
      return next;
    });
    if (editingId === id && editMode === mode) {
      setEditingId(null);
      setEditMode(null);
    }
    pushToast(`${t.delete} ✓`);
  };

  return (
    <div className="apps-panel">
      <div className="apps-panel-header">{tabKey === 'commChannels' ? t.tabCommChannels : t.applications}</div>
      <div className="table-scroll">
        <table className="apps-table">
          <thead>
            <tr>
              {!hideVisibility && <th className="col-vis">{wrapTwo(t.colVisibility)}</th>}
              <th>{wrapTwo(t.colName)}</th>
              <th>{wrapTwo(t.colPriceType)}</th>
              <th>{wrapTwo(t.colPriceValue)}</th>
              <th>{wrapTwo(t.colFirstActivation)}</th>
              {isComm && <th>{wrapTwo(t.colPurchaseDate)}</th>}
              <th>{wrapTwo(isComm ? t.colPaidDate : t.colActivationDate)}</th>
              <th>{wrapTwo(t.colRenewDate)}</th>
              <th>{wrapTwo(t.colStatus)}</th>
              <th className="col-action">{wrapTwo(t.colAction)}</th>
            </tr>
          </thead>
          <tbody>
            {apps.map((app) =>
            <React.Fragment key={app.id}>
                <tr className={editingId === app.id ? 'row-editing' : ''}>
                  {!hideVisibility && <td><VisibilityToggle on={app.visible} disabled={isComm && !!app.purchaseDate} title={isComm && app.purchaseDate ? (t.visLockedHint || 'Visibility can’t be changed — this commchannel has already been purchased.') : undefined} onChange={() => toggleVis(app.id)} /></td>}
                  <td className="name-cell">{app.name}</td>
                  <td>{app.priceType}</td>
                  <td>
                    {app.priceValue ?
                  <span className="price-val"><SAR /> {app.priceValue.toLocaleString()}</span> :
                  '—'}
                  </td>
                  <td className="muted-cell">{formatDMY(app.firstActivation) || '-----'}</td>
                  {isComm && <td className="muted-cell">{formatDMY(app.purchaseDate) || '-----'}</td>}
                  <td className="muted-cell">{formatDMY(app.activation) || '-----'}</td>
                  <td className="muted-cell">{formatDMY(app.renew) || '-----'}</td>
                  <td>
                    {!app.visible || (!app.firstActivation && app.status !== 'paid') ?
                  '-----' :
                  <StatusBadge status={app.status} t={t} />
                  }
                  </td>
                  <td className="col-action">
                    <div className="row-action-stack">
                      {pendingMap[app.id] && (
                        <button
                          className={`row-toggle-btn ${expandedId === app.id ? 'open' : ''}`}
                          onClick={(e) => {e.stopPropagation();setExpandedId(expandedId === app.id ? null : app.id);}}
                          aria-label="Toggle pending changes">
                          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
                            <polyline points="6 9 12 15 18 9" />
                          </svg>
                        </button>
                      )}
                      <div className="row-menu-wrap">
                        <button
                        className={`row-action-btn ${menuFor === app.id ? 'open' : ''}`}
                        onClick={(e) => {e.stopPropagation();setMenuFor(menuFor === app.id ? null : app.id);}}>
                          <IcMore size={16} stroke={2} />
                        </button>
                        {menuFor === app.id &&
                      <RowActionsMenu
                        t={t}
                        isComm={isComm}
                        status={app.status}
                        onClose={() => setMenuFor(null)}
                        onAction={(action) => handleAction(app.id, action)} />
                      }
                      </div>
                    </div>
                  </td>
                </tr>
                {expandedId === app.id && (() => {
                  const p = pendingMap[app.id];
                  const showType = (editingId === app.id && editMode === 'type') || (p && p.type);
                  const showValue = (editingId === app.id && editMode === 'value') || (p && p.value);
                  return (
                    <>
                      {showType && (
                        <EditRow
                          app={app}
                          mode="type"
                          uiMode={editingId === app.id && editMode === 'type' ? 'edit' : 'view'}
                          pending={p?.type}
                          t={t}
                          hideVisibility={hideVisibility}
                          isComm={isComm}
                          onCancel={() => {setEditingId(null);setEditMode(null);if(!p?.type)setExpandedId(null);}}
                          onSave={(next) => handleSet(app.id, next)}
                          onEditAgain={() => {setEditingId(app.id);setEditMode('type');setUiMode('edit');}}
                          onRemove={() => removePending(app.id, 'type')} />
                      )}
                      {showValue && (
                        <EditRow
                          app={app}
                          mode="value"
                          uiMode={editingId === app.id && editMode === 'value' ? 'edit' : 'view'}
                          pending={p?.value}
                          t={t}
                          hideVisibility={hideVisibility}
                          isComm={isComm}
                          onCancel={() => {setEditingId(null);setEditMode(null);if(!p?.value)setExpandedId(null);}}
                          onSave={(next) => handleSet(app.id, next)}
                          onEditAgain={() => {setEditingId(app.id);setEditMode('value');setUiMode('edit');}}
                          onRemove={() => removePending(app.id, 'value')} />
                      )}
                    </>);
                })()}
              </React.Fragment>
            )}
          </tbody>
        </table>
      </div>
      <div className="table-footer-wrap">
        <TablePagination
          total={apps.length}
          page={appsPage}
          pageSize={appsPageSize}
          onPageChange={setAppsPage}
          onPageSizeChange={(n) => { setAppsPageSize(n); setAppsPage(1); }}
          t={t}
        />
      </div>
      {showIB &&
        <InsufficientBalanceModal
          t={t}
          onCancel={() => setShowIB(false)}
          onProceed={(items) => {
            setShowIB(false);
            const first = items[0]?.name || '';
            if (ibTargetId) {
              const today = formatMdy(new Date());
              setApps((a) => a.map((x) => {
                if (x.id !== ibTargetId) return x;
                if (isComm) {
                  // First purchase (never activated) → "Paid" (awaiting activation); otherwise a renewal → Active.
                  if (!x.firstActivation) return { ...x, status: 'paid', purchaseDate: x.purchaseDate || today, activation: today };
                  return { ...x, status: 'active', activation: today };
                }
                return { ...x, status: 'active' };
              }));
            }
            pushToast(`${t.ibProceed} ✓ — ${first}`);
          }} />
      }
      {visWarn &&
        <div className="vis-warn-overlay" onClick={() => setVisWarn(null)}>
          <div className="vis-warn-modal" onClick={(e) => e.stopPropagation()}>
            <div className="vis-warn-ic">
              <svg viewBox="0 0 24 24" width="28" height="28" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
            </div>
            <div className="vis-warn-title">{t.visWarnTitle}</div>
            <div className="vis-warn-msg">{t.visWarnMsg}</div>
            <div className="vis-warn-actions">
              <button className="btn btn-secondary" onClick={() => setVisWarn(null)}>{t.visWarnCancel}</button>
              <button className="btn btn-primary" onClick={confirmVis}>{t.visWarnContinue}</button>
            </div>
          </div>
        </div>
      }
    </div>);

};

window.ApplicationsPage = ApplicationsPage;