let pushState = {
  members: [],
  groups: [],
  walks: [],
  batches: [],
  presets: [],
  presetUseCases: {},
  presetVariables: {},
  presetsInstalled: false,
  selectedWalkId: 0,
  selectedMembers: new Set(),
  selectedGroups: new Set(),
  nativePush: {configuration: {configured:false, message:'Not configured'}, registered_member_count: 0},
  whatsapp: {
    configuration: {configured:false, authenticated:false, message:'Not configured', limits:{}},
    queue: {schema_ready:false, remaining_today:0, today:{}, limits:{}}
  },
  whatsappPreviewToken: '',
  lastPreview: null
};

const pushEsc = value => Pyrk.esc(value ?? '');

function cleanRichNotificationHtml(html) {
  const template = document.createElement('template');
  template.innerHTML = String(html || '');

  const allowed = new Set(['P','BR','STRONG','B','EM','I','U','UL','OL','LI','A','H3','H4','BLOCKQUOTE']);
  const walker = document.createTreeWalker(template.content, NodeFilter.SHOW_ELEMENT);
  const remove = [];

  while (walker.nextNode()) {
    const el = walker.currentNode;
    if (!allowed.has(el.tagName)) {
      remove.push(el);
      continue;
    }

    [...el.attributes].forEach(attr => {
      const name = attr.name.toLowerCase();
      if (name.startsWith('on') || name === 'style' || name === 'class' || name === 'id') {
        el.removeAttribute(attr.name);
      }
    });

    if (el.tagName === 'A') {
      const href = el.getAttribute('href') || '#';
      if (/^\s*javascript:/i.test(href)) el.setAttribute('href', '#');
      el.setAttribute('target', '_blank');
      el.setAttribute('rel', 'noopener noreferrer');
    }
  }

  remove.forEach(el => el.replaceWith(...el.childNodes));
  return template.innerHTML.trim();
}

function richMessageText() {
  const editor = document.getElementById('pushRichEditor');
  return String(editor?.innerText || '').replace(/\u00a0/g, ' ').trim();
}

function syncRichMessageFields() {
  const editor = document.getElementById('pushRichEditor');
  const text = richMessageText();
  const html = cleanRichNotificationHtml(editor?.innerHTML || '');
  const message = document.getElementById('pushMessage');
  const messageHtml = document.getElementById('pushMessageHtml');
  if (message) message.value = text;
  if (messageHtml) messageHtml.value = html;
  return {text, html};
}

function initRichNotificationEditor() {
  const editor = document.getElementById('pushRichEditor');
  if (!editor || editor.dataset.ready === '1') return;
  editor.dataset.ready = '1';

  editor.addEventListener('input', () => { syncRichMessageFields(); invalidateWhatsAppPreview(); });
  editor.addEventListener('paste', e => {
    e.preventDefault();
    const text = (e.clipboardData || window.clipboardData).getData('text/plain');
    document.execCommand('insertText', false, text);
    syncRichMessageFields();
  });

  document.querySelectorAll('[data-rich-command]').forEach(btn => {
    btn.addEventListener('click', () => {
      editor.focus();
      document.execCommand(btn.dataset.richCommand, false, null);
      syncRichMessageFields();
    });
  });

  document.querySelectorAll('[data-rich-block]').forEach(btn => {
    btn.addEventListener('click', () => {
      editor.focus();
      document.execCommand('formatBlock', false, btn.dataset.richBlock);
      syncRichMessageFields();
    });
  });

  document.querySelectorAll('[data-rich-link]').forEach(btn => {
    btn.addEventListener('click', () => {
      editor.focus();
      const url = prompt('Enter link URL');
      if (!url) return;
      const safeUrl = /^(https?:\/\/|mailto:|tel:)/i.test(url.trim()) ? url.trim() : 'https://' + url.trim();
      document.execCommand('createLink', false, safeUrl);
      syncRichMessageFields();
    });
  });
}



function pushIds(set) {
  return JSON.stringify(Array.from(set).map(Number).filter(Boolean));
}

function pushScope() {
  return document.getElementById('pushTargetScope')?.value || 'all_members';
}

function pushPayload(action) {
  return {
    action,
    subject: document.getElementById('pushSubject')?.value || '',
    message: syncRichMessageFields().text,
    message_html: syncRichMessageFields().html,
    target_scope: pushScope(),
    delivery_email: document.getElementById('deliveryEmail')?.checked ? 1 : 0,
    delivery_web: document.getElementById('deliveryWeb')?.checked ? 1 : 0,
    delivery_whatsapp: document.getElementById('deliveryWhatsapp')?.checked ? 1 : 0,
    delivery_native: document.getElementById('deliveryNative')?.checked ? 1 : 0,
    whatsapp_consent_confirmed: document.getElementById('whatsappConsentConfirmed')?.checked ? 1 : 0,
    whatsapp_preview_token: pushState.whatsappPreviewToken || '',
    walk_id: Number(document.getElementById('pushWalkId')?.value || pushState.selectedWalkId || 0),
    member_ids: pushIds(pushState.selectedMembers),
    group_ids: pushIds(pushState.selectedGroups),
    push_preset_id: Number(document.getElementById('pushPresetId')?.value || 0)
  };
}

function renderPushStats() {
  const memberCount = document.getElementById('pushMemberCount');
  const groupCount = document.getElementById('pushGroupCount');
  const nativeMemberCount = document.getElementById('pushNativeMemberCount');
  const batchCount = document.getElementById('pushBatchCount');
  if (memberCount) memberCount.textContent = String(pushState.members.length);
  if (groupCount) groupCount.textContent = String(pushState.groups.length);
  if (nativeMemberCount) nativeMemberCount.textContent = String(Number(pushState.nativePush?.registered_member_count || 0));
  if (batchCount) batchCount.textContent = String(pushState.batches.length);
}

function syncPushChannelCards() {
  document.querySelectorAll('[data-push-channel-card]').forEach(card => {
    const input = card.querySelector('input[type="checkbox"]');
    if (!input) return;
    card.classList.toggle('is-selected', !!input.checked);
    card.classList.toggle('is-disabled', !!input.disabled);
    card.setAttribute('aria-disabled', input.disabled ? 'true' : 'false');
  });

  const whatsappSelected = !!document.getElementById('deliveryWhatsapp')?.checked;
  const safetyPanel = document.getElementById('whatsappSafetyPanel');
  if (safetyPanel) safetyPanel.hidden = !whatsappSelected;
}

function setPushStatusBadge(element, label, state) {
  if (!element) return;
  element.textContent = label;
  element.classList.remove('is-ready', 'is-warning', 'is-error');
  if (state) element.classList.add(state);
}

function renderNativePushStatus() {
  const nativeConfig = pushState.nativePush?.configuration || {};
  const androidReady = !!nativeConfig.android?.configured;
  const iosReady = !!nativeConfig.ios?.configured;
  const configured = !!nativeConfig.configured;
  const registered = Number(pushState.nativePush?.registered_member_count || 0);
  const nativeHint = document.getElementById('nativePushHint');
  const nativeCheckbox = document.getElementById('deliveryNative');

  setPushStatusBadge(
    document.getElementById('nativeAndroidStatus'),
    `Android: ${androidReady ? 'ready' : 'setup required'}`,
    androidReady ? 'is-ready' : 'is-warning'
  );
  setPushStatusBadge(
    document.getElementById('nativeIosStatus'),
    `iOS: ${iosReady ? 'ready' : 'setup required'}`,
    iosReady ? 'is-ready' : 'is-warning'
  );
  setPushStatusBadge(
    document.getElementById('nativeDeviceStatus'),
    `${registered} app member${registered === 1 ? '' : 's'}`,
    registered > 0 ? 'is-ready' : ''
  );

  if (nativeHint) {
    nativeHint.textContent = configured
      ? `${registered} member${registered === 1 ? '' : 's'} currently have an active app device. Phone push is available for the configured platform${androidReady && iosReady ? 's' : ''}.`
      : (nativeConfig.message || 'Firebase for Android or APNs for iOS must be configured before phone push can be selected.');
  }

  if (nativeCheckbox) {
    nativeCheckbox.disabled = !configured;
    if (!configured) nativeCheckbox.checked = false;
  }

  syncPushChannelCards();
}

function renderWhatsAppStatus() {
  const config = pushState.whatsapp?.configuration || {};
  const queue = pushState.whatsapp?.queue || {};
  const limits = config.limits || queue.limits || {};
  const configured = !!config.configured;
  const authenticated = !!config.authenticated;
  const schemaReady = !!queue.schema_ready;
  const remaining = Number(queue.remaining_today || 0);
  const whatsappCheckbox = document.getElementById('deliveryWhatsapp');
  const providerHint = document.getElementById('whatsappProviderHint');

  let providerLabel = 'Provider: setup required';
  let providerState = 'is-warning';
  if (configured && authenticated) {
    providerLabel = 'UltraMsg: authenticated';
    providerState = 'is-ready';
  } else if (configured) {
    providerLabel = `UltraMsg: ${String(config.instance_status || 'test required').replace(/_/g, ' ')}`;
    providerState = config.instance_status === 'connection_failed' ? 'is-error' : 'is-warning';
  }

  setPushStatusBadge(document.getElementById('whatsappProviderStatus'), providerLabel, providerState);
  setPushStatusBadge(
    document.getElementById('whatsappQueueStatus'),
    schemaReady ? `Queue: ${Number(queue.today?.queued || 0)} waiting` : 'Queue: migration required',
    schemaReady ? 'is-ready' : 'is-warning'
  );
  setPushStatusBadge(
    document.getElementById('whatsappDailyStatus'),
    `${remaining} daily slot${remaining === 1 ? '' : 's'} left`,
    remaining > 0 ? '' : 'is-warning'
  );

  if (providerHint) {
    providerHint.textContent = config.message || (configured
      ? 'UltraMsg is configured. Use Test connection to verify the linked WhatsApp session.'
      : 'Add the UltraMsg instance ID and private token file to the server configuration.');
  }

  const batchLimit = document.getElementById('whatsappBatchLimit');
  const remainingToday = document.getElementById('whatsappRemainingToday');
  const workerPace = document.getElementById('whatsappWorkerPace');
  const duplicateWindow = document.getElementById('whatsappDuplicateWindow');
  if (batchLimit) batchLimit.textContent = `${Number(limits.max_per_batch || 50)} maximum`;
  if (remainingToday) remainingToday.textContent = `${remaining} remaining of ${Number(limits.max_per_day || 100)}`;
  if (workerPace) workerPace.textContent = `${Number(limits.messages_per_run || 5)} per cron run`;
  if (duplicateWindow) duplicateWindow.textContent = `${Number(limits.duplicate_window_hours || 24)} hours`;

  if (whatsappCheckbox) {
    const selectable = configured && schemaReady;
    whatsappCheckbox.disabled = !selectable;
    if (!selectable) whatsappCheckbox.checked = false;
  }

  syncPushChannelCards();
}

async function loadWhatsAppStatus(showToast = false) {
  const button = document.getElementById('testWhatsAppConnectionBtn');
  if (button) {
    button.disabled = true;
    button.textContent = 'Testing…';
  }

  const res = await Pyrk.get('manual_notifications.php', {action: 'whatsapp_status'});
  if (button) {
    button.disabled = false;
    button.textContent = 'Test connection';
  }

  if (!res.ok) {
    if (showToast) Pyrk.toast('pushMsg', res);
    return;
  }

  pushState.whatsapp = res.data || pushState.whatsapp;
  renderWhatsAppStatus();
  if (showToast) {
    const ready = !!pushState.whatsapp?.configuration?.authenticated;
    Pyrk.toast('pushMsg', {
      ok: ready,
      message: pushState.whatsapp?.configuration?.message || (ready ? 'UltraMsg is ready.' : 'UltraMsg needs attention.')
    });
  }
}

function invalidateWhatsAppPreview() {
  pushState.whatsappPreviewToken = '';
  pushState.lastPreview = null;
}

function syncPushAudience() {
  const scope = pushScope();
  const groupBox = document.getElementById('pushGroupSelector');
  const memberBox = document.getElementById('pushMemberSelector');
  const walkBox = document.getElementById('pushWalkSelector');
  const hint = document.getElementById('pushAudienceHint');
  const inlineHint = document.getElementById('pushAudienceInlineHint');

  if (groupBox) groupBox.hidden = scope !== 'selected_groups';
  if (memberBox) memberBox.hidden = scope !== 'selected_members';
  if (walkBox) walkBox.hidden = scope !== 'walk_registrants';

  let text = 'All active members will receive this notification.';
  if (scope === 'selected_groups') {
    text = `${pushState.selectedGroups.size} team/group(s) selected.`;
  } else if (scope === 'selected_members') {
    text = `${pushState.selectedMembers.size} member(s) selected.`;
  } else if (scope === 'walk_registrants') {
    const walk = selectedWalk();
    text = walk ? `Registrants of ${walk.title || 'the selected walk'} will receive this reminder.` : 'Choose a walk for reminder recipients.';
  }
  if (hint) hint.textContent = text;
  if (inlineHint) inlineHint.textContent = text;
}


function formatWalkDate(value) {
  const s = String(value || '').slice(0, 10);
  const m = s.match(/^(\d{4})-(\d{2})-(\d{2})$/);
  return m ? `${m[3]}/${m[2]}/${m[1]}` : s;
}

function selectedWalk() {
  const id = Number(document.getElementById('pushWalkId')?.value || pushState.selectedWalkId || 0);
  return (pushState.walks || []).find(w => Number(w.id) === id) || null;
}

function fillWalkSelect() {
  const select = document.getElementById('pushWalkId');
  if (!select) return;
  select.innerHTML = '<option value="">No walk selected</option>' + (pushState.walks || []).map(w => `<option value="${Number(w.id)}">${pushEsc(w.title)} · ${formatWalkDate(w.walk_date)} ${pushEsc(String(w.start_time || '').slice(0,5))} · ${Number(w.registered_count || 0)} registrants</option>`).join('');
}

function renderWalks() {
  const list = document.getElementById('pushWalkList');
  if (!list) return;
  const q = (document.getElementById('pushWalkSearch')?.value || '').toLowerCase().trim();
  const rows = (pushState.walks || []).filter(w => !q || `${w.title || ''} ${w.walk_date || ''} ${w.status || ''}`.toLowerCase().includes(q));
  const current = Number(document.getElementById('pushWalkId')?.value || 0);
  list.innerHTML = rows.map(w => {
    const id = Number(w.id);
    const checked = id === current;
    return `<label class="push-recipient-row ${checked ? 'is-selected' : ''}">
      <input type="radio" name="pushWalkRadio" value="${id}" ${checked ? 'checked' : ''}>
      <span class="recipient-avatar">🚶</span>
      <span><strong>${pushEsc(w.title || 'Walk')}</strong><small>${formatWalkDate(w.walk_date)} ${pushEsc(String(w.start_time || '').slice(0,5))} · ${Number(w.registered_count || 0)} registrants</small></span>
    </label>`;
  }).join('') || '<p class="muted">No upcoming walks found.</p>';
}

function pushPlainTextToHtml(value) {
  const escaped = pushEsc(String(value || ''));
  return escaped.split(/\n{2,}/).map(block => `<p>${block.replace(/\n/g, '<br>')}</p>`).join('');
}

function pushPresetLabel(preset) {
  const context = pushState.presetUseCases[preset?.use_case] || String(preset?.use_case || 'custom').replace(/_/g, ' ');
  return `${preset?.preset_name || 'Preset'} · ${context}${Number(preset?.is_default) === 1 ? ' · Default' : ''}`;
}

function pushPresetById(id) {
  return (pushState.presets || []).find(preset => Number(preset.id) === Number(id)) || null;
}

function renderPushPresetOptions() {
  const select = document.getElementById('pushPreset');
  const help = document.getElementById('pushPresetHelp');
  if (!select) return;
  const previous = String(select.value || '');
  if (!pushState.presetsInstalled) {
    select.innerHTML = '<option value="">Push presets not installed</option>';
    select.disabled = true;
    if (help) help.textContent = 'Import migration 044_push_notification_presets.sql first.';
    return;
  }
  select.disabled = false;
  const groups = new Map();
  (pushState.presets || []).filter(p => Number(p.is_active) === 1).forEach(preset => {
    const key = String(preset.use_case || 'custom');
    if (!groups.has(key)) groups.set(key, []);
    groups.get(key).push(preset);
  });
  select.innerHTML = '<option value="">Choose an active Push preset…</option>' + Array.from(groups.entries()).map(([key, rows]) => {
    const label = pushState.presetUseCases[key] || key.replace(/_/g, ' ');
    return `<optgroup label="${pushEsc(label)}">${rows.map(p => `<option value="${Number(p.id)}">${pushEsc(pushPresetLabel(p))}</option>`).join('')}</optgroup>`;
  }).join('');
  if (previous && pushPresetById(previous)) select.value = previous;
  if (help) help.textContent = pushState.presets.length ? 'Select a preset and click Apply preset. You can edit the composed message without changing the saved preset.' : 'No active Push presets are available.';
}

function renderPushPresetVariables() {
  const box = document.getElementById('pushPresetVariableChips');
  if (!box) return;
  box.innerHTML = Object.entries(pushState.presetVariables || {}).map(([token, label]) => `<button type="button" data-push-preset-token="${pushEsc(token)}" title="${pushEsc(label)}">${pushEsc(token)}</button>`).join('');
  box.querySelectorAll('[data-push-preset-token]').forEach(button => button.addEventListener('click', () => insertPushPresetVariable(String(button.dataset.pushPresetToken || ''))));
}

async function loadPushPresets() {
  try {
    const res = await Pyrk.get('push_notification_presets.php', {action:'list', active_only:1});
    if (!res.ok) throw new Error(res.message || 'Could not load Push presets.');
    pushState.presetsInstalled = Number(res.data?.installed || 0) === 1;
    pushState.presets = Array.isArray(res.data?.presets) ? res.data.presets : [];
    pushState.presetUseCases = res.data?.use_cases || {};
    pushState.presetVariables = res.data?.variables || {};
  } catch (error) {
    pushState.presetsInstalled = false;
    pushState.presets = [];
    const help = document.getElementById('pushPresetHelp');
    if (help) help.textContent = error?.message || 'Could not load Push presets.';
  }
  renderPushPresetOptions();
  renderPushPresetVariables();
}

function applyWalkPreset() {
  const preset = pushPresetById(document.getElementById('pushPreset')?.value || '');
  if (!preset) {
    Pyrk.toast('pushMsg', {ok:false, message:'Choose an active Push preset first.'});
    return;
  }
  document.getElementById('pushSubject').value = String(preset.subject_template || '');
  const editor = document.getElementById('pushRichEditor');
  if (editor) {
    editor.innerHTML = pushPlainTextToHtml(String(preset.message_template || ''));
    syncRichMessageFields();
  }
  const presetId = document.getElementById('pushPresetId');
  if (presetId) presetId.value = String(preset.id || '');
  const walk = selectedWalk();
  if (walk && String(preset.use_case || '').startsWith('walk_')) {
    document.getElementById('pushTargetScope').value = 'walk_registrants';
    pushState.selectedWalkId = Number(walk.id || 0);
    syncPushAudience();
    renderWalks();
  }
  const help = document.getElementById('pushPresetHelp');
  if (help) help.textContent = `Applied “${preset.preset_name || 'preset'}”. Unknown or unresolved variables will be blocked by the server.`;
}

function insertPushPresetVariable(token) {
  if (!token) return;
  const subject = document.getElementById('pushSubject');
  const editor = document.getElementById('pushRichEditor');
  if (document.activeElement === subject) {
    const start = Number.isInteger(subject.selectionStart) ? subject.selectionStart : subject.value.length;
    const end = Number.isInteger(subject.selectionEnd) ? subject.selectionEnd : start;
    subject.value = subject.value.slice(0, start) + token + subject.value.slice(end);
    const caret = start + token.length;
    subject.focus(); subject.setSelectionRange(caret, caret);
  } else if (editor) {
    editor.focus();
    document.execCommand('insertText', false, token);
    syncRichMessageFields();
  }
  invalidateWhatsAppPreview();
}

function useWalkAudience() {
  const walkId = Number(document.getElementById('pushWalkId')?.value || 0);
  if (!walkId) {
    Pyrk.toast('pushMsg', {ok:false, message:'Choose a walk first.'});
    return;
  }
  pushState.selectedWalkId = walkId;
  document.getElementById('pushTargetScope').value = 'walk_registrants';
  syncPushAudience();
  renderWalks();
}

function renderAttachments() {
  const box = document.getElementById('pushAttachmentList');
  const input = document.getElementById('pushAttachments');
  if (!box || !input) return;
  const files = Array.from(input.files || []);
  box.innerHTML = files.length ? files.map(f => `<span class="attachment-chip">📎 ${pushEsc(f.name)} <small>${Math.ceil(f.size/1024)} KB</small></span>`).join('') : '';
}

function pushFormData(payload) {
  const fd = new FormData();
  Object.entries(payload).forEach(([key, value]) => fd.append(key, value ?? ''));
  Array.from(document.getElementById('pushAttachments')?.files || []).forEach(file => fd.append('attachments[]', file));
  return fd;
}


function renderGroups() {
  const list = document.getElementById('pushGroupList');
  if (!list) return;
  const q = (document.getElementById('pushGroupSearch')?.value || '').toLowerCase().trim();
  const rows = (pushState.groups || []).filter(g => !q || `${g.group_name || ''} ${g.description || ''}`.toLowerCase().includes(q));

  list.innerHTML = rows.map(g => {
    const id = Number(g.id);
    const disabled = String(g.status || 'active') !== 'active';
    const checked = pushState.selectedGroups.has(id);
    return `<label class="push-recipient-row ${checked ? 'is-selected' : ''} ${disabled ? 'is-disabled' : ''}">
      <input type="checkbox" value="${id}" ${checked ? 'checked' : ''} ${disabled ? 'disabled' : ''}>
      <span class="recipient-avatar">👥</span>
      <span><strong>${pushEsc(g.group_name || 'Team')}</strong><small>${Number(g.member_count || 0)} active members · ${pushEsc(g.status || 'active')}</small></span>
    </label>`;
  }).join('') || '<p class="muted">No teams/groups found.</p>';
  syncPushAudience();
}

function renderMembers() {
  const list = document.getElementById('pushMemberList');
  if (!list) return;
  const q = (document.getElementById('pushMemberSearch')?.value || '').toLowerCase().trim();
  const rows = (pushState.members || []).filter(m => !q || `${m.full_name || ''} ${m.email || ''} ${m.mobile || ''}`.toLowerCase().includes(q));

  list.innerHTML = rows.map(m => {
    const id = Number(m.id);
    const checked = pushState.selectedMembers.has(id);
    const initial = String(m.full_name || '?').slice(0,1).toUpperCase();
    return `<label class="push-recipient-row ${checked ? 'is-selected' : ''}">
      <input type="checkbox" value="${id}" ${checked ? 'checked' : ''}>
      <span class="recipient-avatar">${pushEsc(initial)}</span>
      <span><strong>${pushEsc(m.full_name || 'Member')}</strong><small>${pushEsc(m.email || 'No email')}${m.mobile ? ' · ' + pushEsc(m.mobile) : ''}</small></span>
    </label>`;
  }).join('') || '<p class="muted">No members found.</p>';
  syncPushAudience();
}

function renderHistory() {
  const tbody = document.getElementById('pushHistoryBody');
  if (!tbody) return;

  tbody.innerHTML = (pushState.batches || []).map(b => {
    const attachments = Number(b.attachment_count || 0);
    return `<tr>
      <td><strong>${pushEsc(b.subject)}</strong><small>${pushEsc(String(b.message || '').replace(/<[^>]*>/g, ' ').slice(0, 100))}${attachments ? ` · 📎 ${attachments}` : ''}</small></td>
      <td>${b.walk_title ? `<strong>${pushEsc(b.walk_title)}</strong><small>${formatWalkDate(b.walk_date)}</small>` : '<span class="muted">—</span>'}</td>
      <td>${pushEsc(audienceLabel(b.target_scope))}</td>
      <td>${pushEsc(deliveryLabel(b))}</td>
      <td>${Number(b.total_recipients || b.recipient_log_count || 0)}</td>
      <td>${pushEsc(notificationResultLabel(b))}</td>
      <td>${pushEsc(b.created_by_name || 'Admin')}</td>
      <td>${pushEsc(b.created_at || '')}</td>
      <td><button class="btn btn-light btn-small" type="button" data-history-detail="${Number(b.id)}">View</button></td>
    </tr>`;
  }).join('') || '<tr><td colspan="9" class="muted">No notifications match your filters.</td></tr>';
}


function fillHistoryWalkSelect() {
  const select = document.getElementById('pushHistoryWalk');
  if (!select) return;
  select.innerHTML = '<option value="">All walks</option>' + (pushState.walks || []).map(w => `<option value="${Number(w.id)}">${pushEsc(w.title)} · ${formatWalkDate(w.walk_date)}</option>`).join('');
}

function historyFilters() {
  return {
    action: 'history',
    q: document.getElementById('pushHistorySearch')?.value || '',
    channel: document.getElementById('pushHistoryChannel')?.value || '',
    audience: document.getElementById('pushHistoryAudience')?.value || '',
    walk_id: document.getElementById('pushHistoryWalk')?.value || '',
    date_from: document.getElementById('pushHistoryFrom')?.value || '',
    date_to: document.getElementById('pushHistoryTo')?.value || '',
    limit: 200
  };
}

function deliveryLabel(b) {
  return [
    Number(b.delivery_web || 0) === 1 ? 'Web' : '',
    Number(b.delivery_native || 0) === 1 ? 'Phone push' : '',
    Number(b.delivery_email || 0) === 1 ? 'Email' : '',
    Number(b.delivery_whatsapp || 0) === 1 ? 'WhatsApp' : ''
  ].filter(Boolean).join(' + ') || '—';
}

function audienceLabel(scope) {
  return String(scope || '').replace(/_/g, ' ') || '—';
}

function notificationResultLabel(b) {
  const whatsapp = Number(b.whatsapp_queued_count || 0) > 0
    ? `${Number(b.whatsapp_sent_count || 0)} sent / ${Number(b.whatsapp_queued_count || 0)} queued WhatsApp`
    : `${Number(b.whatsapp_sent_count || 0)} WhatsApp`;
  return `${Number(b.web_sent_count || 0)} web · ${Number(b.native_sent_count || 0)} phone · ${Number(b.email_sent_count || 0)} email · ${whatsapp}`;
}

function selectedAttachmentNames() {
  return Array.from(document.getElementById('pushAttachments')?.files || []).map(f => ({name:f.name, size:f.size}));
}

async function loadPushHistory() {
  bindPushHistoryEvents();
  const res = await Pyrk.get('manual_notifications.php', historyFilters());
  if (!res.ok) {
    Pyrk.toast('pushMsg', res);
    return;
  }
  pushState.batches = res.data.rows || [];
  renderHistory();
}

async function loadPushHistoryDetail(id) {
  const res = await Pyrk.get('manual_notifications.php', {action:'detail', id});
  const box = document.getElementById('pushHistoryDetail');
  if (!box) return;
  if (!res.ok) {
    box.hidden = false;
    box.innerHTML = `<p class="notice bad">${pushEsc(res.message || 'Could not load notification detail.')}</p>`;
    return;
  }

  const batch = res.data.batch || {};
  const recipients = res.data.recipients || [];
  const attachments = res.data.attachments || [];
  const queuedWhatsApp = Number(batch.whatsapp_queued_count || 0);

  box.hidden = false;
  box.innerHTML = `
    <div class="section-head mini-head">
      <div>
        <p class="eyebrow">Notification detail</p>
        <h3>${pushEsc(batch.subject || 'Notification')}</h3>
        <p class="muted small">${pushEsc(deliveryLabel(batch))} · ${Number(batch.total_recipients || recipients.length || 0)} recipient(s) · ${pushEsc(batch.created_at || '')}</p>
      </div>
      <div class="inline-controls">
        ${queuedWhatsApp > 0 ? `<button class="btn btn-light btn-small" type="button" data-cancel-whatsapp-batch="${Number(batch.id || 0)}">Cancel queued WhatsApp (${queuedWhatsApp})</button>` : ''}
        <button class="btn btn-light btn-small" type="button" id="closePushHistoryDetail" data-close-history-detail>Close</button>
      </div>
    </div>
    <div class="history-message-preview">${batch.message || ''}</div>
    ${attachments.length ? `<div class="history-attachments">${attachments.map(a => `<a href="../${pushEsc(a.file_path || '')}" target="_blank" rel="noopener noreferrer">📎 ${pushEsc(a.original_name || 'Attachment')}</a>`).join('')}</div>` : ''}
    <div class="table-wrap small-table-wrap">
      <table class="pro-table">
        <thead><tr><th>Member</th><th>Email</th><th>Mobile</th><th>Email</th><th>Web</th><th>Phone push</th><th>WhatsApp</th><th>Error</th></tr></thead>
        <tbody>${recipients.map(r => `<tr>
          <td>${pushEsc(r.full_name || ('#' + r.user_id))}</td>
          <td>${pushEsc(r.email || '')}</td>
          <td>${pushEsc(r.mobile || r.user_mobile || '')}</td>
          <td>${pushEsc(r.email_status || '—')}</td>
          <td>${pushEsc(r.web_status || '—')}</td>
          <td>${pushEsc(r.native_status || '—')}</td>
          <td>${pushEsc(r.whatsapp_status || '—')}</td>
          <td>${pushEsc(r.error_message || '')}</td>
        </tr>`).join('') || '<tr><td colspan="8" class="muted">No recipient log.</td></tr>'}</tbody>
      </table>
    </div>`;

  document.getElementById('closePushHistoryDetail')?.addEventListener('click', () => { box.hidden = true; box.innerHTML = ''; });
  box.querySelector('[data-cancel-whatsapp-batch]')?.addEventListener('click', async e => {
    const batchId = Number(e.currentTarget.dataset.cancelWhatsappBatch || 0);
    if (!batchId || !confirm('Cancel all WhatsApp messages from this batch that have not been sent yet?')) return;
    e.currentTarget.disabled = true;
    const cancelRes = await Pyrk.post('manual_notifications.php', {action:'cancel_whatsapp_batch', batch_id:batchId});
    Pyrk.toast('pushMsg', cancelRes);
    if (cancelRes.ok) {
      await loadPushHistory();
      await loadPushHistoryDetail(batchId);
      await loadWhatsAppStatus(false);
    } else {
      e.currentTarget.disabled = false;
    }
  });
  box.scrollIntoView({behavior:'smooth', block:'nearest'});
}
window.loadPushHistoryDetail = loadPushHistoryDetail;



function bindPushHistoryEvents() {
  const body = document.getElementById('pushHistoryBody');
  if (body && body.dataset.historyBound !== '1') {
    body.dataset.historyBound = '1';
    body.addEventListener('click', e => {
      const btn = e.target.closest('[data-history-detail]');
      if (!btn) return;
      e.preventDefault();
      e.stopPropagation();
      const id = Number(btn.dataset.historyDetail || 0);
      if (id > 0) loadPushHistoryDetail(id);
    });
  }

  const detail = document.getElementById('pushHistoryDetail');
  if (detail && detail.dataset.historyDetailBound !== '1') {
    detail.dataset.historyDetailBound = '1';
    detail.addEventListener('click', e => {
      const btn = e.target.closest('[data-close-history-detail]');
      if (!btn) return;
      e.preventDefault();
      detail.hidden = true;
      detail.innerHTML = '';
    });
  }

  const filterIds = ['pushHistorySearch','pushHistoryChannel','pushHistoryAudience','pushHistoryWalk','pushHistoryFrom','pushHistoryTo'];
  filterIds.forEach(id => {
    const el = document.getElementById(id);
    if (!el || el.dataset.historyFilterBound === '1') return;
    el.dataset.historyFilterBound = '1';

    let timer = null;
    const run = () => {
      clearTimeout(timer);
      timer = setTimeout(loadPushHistory, id === 'pushHistorySearch' ? 250 : 0);
    };

    el.addEventListener(id === 'pushHistorySearch' ? 'input' : 'change', run);
  });

  const refresh = document.getElementById('refreshPushHistory');
  if (refresh && refresh.dataset.historyRefreshBound !== '1') {
    refresh.dataset.historyRefreshBound = '1';
    refresh.addEventListener('click', e => {
      e.preventDefault();
      loadPushHistory();
    });
  }
}


function renderPreview(data) {
  const box = document.getElementById('pushPreviewBox');
  if (!box) return;

  const payload = pushPayload('preview');
  const sample = (data.sample_recipients || []).map(r => `<li>${pushEsc(r.full_name)} <small>${pushEsc(r.email || 'No email')}${r.mobile ? ' · ' + pushEsc(r.mobile) : ''}</small></li>`).join('');
  const files = selectedAttachmentNames();
  const preview = data.preview || {};
  const whatsapp = data.whatsapp || {};
  const whatsappQueue = whatsapp.queue || {};
  const whatsappLimits = whatsapp.configuration?.limits || whatsappQueue.limits || {};
  const whatsappSafety = Number(payload.delivery_whatsapp) ? `
    <section class="preview-whatsapp-safety ${whatsapp.can_queue ? 'is-ready' : 'is-warning'}">
      <strong>${whatsapp.can_queue ? 'WhatsApp queue ready' : 'WhatsApp queue needs attention'}</strong>
      <span>${Number(whatsapp.unique_count || 0)} unique valid · ${Number(whatsapp.duplicate_count || 0)} duplicate skipped · ${Number(whatsapp.invalid_count || 0)} invalid</span>
      <span>Maximum ${Number(whatsappLimits.max_per_batch || 50)} per batch · ${Number(whatsappQueue.remaining_today || 0)} daily slots remaining</span>
    </section>` : '';

  box.innerHTML = `
    <div class="notification-preview-pro">
      <div>
        <strong>${Number(data.recipient_count || 0)} recipients</strong>
        <span>${Number(data.native_count || 0)} app-ready · ${Number(data.email_count || 0)} email-ready · ${Number(data.whatsapp_count || 0)} unique WhatsApp-ready</span>
      </div>
      <div class="preview-channel-row">${deliveryLabel(payload)}</div>
      ${whatsappSafety}
      <article class="preview-message-card">
        <h3>${pushEsc(preview.subject || payload.subject || 'Notification preview')}</h3>
        <div class="preview-message-body">${preview.message_html || payload.message_html || pushEsc(payload.message || '')}</div>
        ${files.length ? `<div class="attachment-list">${files.map(file => `<span class="attachment-chip">📎 ${pushEsc(file.name)} <small>${Math.ceil(file.size/1024)} KB</small></span>`).join('')}</div>` : ''}
      </article>
      <details>
        <summary>Sample recipients</summary>
        <ul>${sample || '<li>No recipients found.</li>'}</ul>
      </details>
    </div>`;
}

async function loadPushCenter() {
  const res = await Pyrk.get('manual_notifications.php', {action: 'overview'});
  if (!res.ok) {
    Pyrk.toast('pushMsg', res);
    return;
  }

  pushState.members = res.data.members || [];
  pushState.groups = res.data.groups || [];
  pushState.walks = res.data.walks || [];
  pushState.batches = res.data.batches || [];
  pushState.nativePush = res.data.native_push || pushState.nativePush;
  pushState.whatsapp = res.data.whatsapp || pushState.whatsapp;
  renderNativePushStatus();
  renderWhatsAppStatus();
  pushState.selectedMembers = new Set(pushState.members.map(m => Number(m.id)));
  pushState.selectedGroups = new Set(pushState.groups.filter(g => String(g.status || 'active') === 'active').map(g => Number(g.id)));

  renderPushStats();
  fillWalkSelect();
  fillHistoryWalkSelect();
  renderWalks();
  renderGroups();
  renderMembers();
  syncPushAudience();
  await loadPushPresets();
  await loadPushHistory();
}

async function previewPush() {
  invalidateWhatsAppPreview();
  const payload = pushPayload('preview');
  const res = await Pyrk.post('manual_notifications.php', payload);
  Pyrk.toast('pushMsg', res);
  if (!res.ok) return;

  pushState.lastPreview = res.data || {};
  pushState.whatsappPreviewToken = String(res.data?.whatsapp?.preview_token || '');
  if (res.data?.whatsapp) {
    pushState.whatsapp = {
      configuration: res.data.whatsapp.configuration || pushState.whatsapp.configuration,
      queue: res.data.whatsapp.queue || pushState.whatsapp.queue
    };
    renderWhatsAppStatus();
  }
  renderPreview(res.data || {});
}

async function sendPush() {
  const payload = pushPayload('send');

  if (!payload.subject.trim()) {
    Pyrk.toast('pushMsg', {ok:false, message:'Subject is required.'});
    return;
  }
  if (!payload.message.trim()) {
    Pyrk.toast('pushMsg', {ok:false, message:'Message is required.'});
    return;
  }
  if (!Number(payload.delivery_email) && !Number(payload.delivery_web) && !Number(payload.delivery_whatsapp) && !Number(payload.delivery_native)) {
    Pyrk.toast('pushMsg', {ok:false, message:'Choose Web notification, Phone push, Email and/or WhatsApp.'});
    return;
  }
  if (payload.target_scope === 'walk_registrants' && !Number(payload.walk_id)) {
    Pyrk.toast('pushMsg', {ok:false, message:'Choose a walk for walk reminder recipients.'});
    return;
  }

  if (Number(payload.delivery_whatsapp)) {
    if (!Number(payload.whatsapp_consent_confirmed)) {
      Pyrk.toast('pushMsg', {ok:false, message:'Confirm member consent before queueing WhatsApp messages.'});
      document.getElementById('whatsappConsentConfirmed')?.focus();
      return;
    }
    if (!pushState.whatsappPreviewToken || !pushState.lastPreview) {
      Pyrk.toast('pushMsg', {ok:false, message:'Preview this exact WhatsApp message and audience before queueing.'});
      return;
    }
    if (!pushState.lastPreview?.whatsapp?.can_queue) {
      Pyrk.toast('pushMsg', {ok:false, message:'The preview shows that this WhatsApp batch cannot be queued safely. Reduce the audience or finish setup.'});
      return;
    }
  }

  const whatsappCount = Number(pushState.lastPreview?.whatsapp?.unique_count || 0);
  const confirmation = Number(payload.delivery_whatsapp)
    ? `Queue ${whatsappCount} unique WhatsApp message(s) and send the other selected channels now?\n\nWhatsApp will be released gradually by the cron worker, not all at once.`
    : 'Send this notification now?';
  if (!confirm(confirmation)) return;

  const topBtn = document.getElementById('sendPushBtn');
  const bottomBtn = document.getElementById('sendPushBtnBottom');
  [topBtn, bottomBtn].forEach(btn => {
    if (!btn) return;
    btn.disabled = true;
    btn.textContent = Number(payload.delivery_whatsapp) ? 'Queueing safely...' : 'Sending...';
  });

  const hasFiles = (document.getElementById('pushAttachments')?.files || []).length > 0;
  const res = hasFiles ? await Pyrk.postForm('manual_notifications.php', pushFormData(payload)) : await Pyrk.post('manual_notifications.php', payload);
  Pyrk.toast('pushMsg', res);
  [topBtn, bottomBtn].forEach(btn => {
    if (!btn) return;
    btn.disabled = false;
    btn.textContent = 'Send notification';
  });

  if (res.ok) {
    invalidateWhatsAppPreview();
    await loadPushCenter();
    renderPreview({
      recipient_count: res.data.total_recipients || 0,
      native_count: res.data.native_sent || 0,
      email_count: res.data.email_sent || 0,
      whatsapp_count: res.data.whatsapp_queued || res.data.whatsapp_sent || 0,
      whatsapp: {
        unique_count: res.data.whatsapp_queued || 0,
        duplicate_count: res.data.whatsapp_skipped || 0,
        invalid_count: res.data.whatsapp_failed || 0,
        can_queue: true,
        configuration: pushState.whatsapp.configuration,
        queue: pushState.whatsapp.queue
      },
      sample_recipients: []
    });
  }
}

document.querySelectorAll('[data-push-channel-card] input[type="checkbox"]').forEach(input => {
  input.addEventListener('change', () => { syncPushChannelCards(); if (input.id === 'deliveryWhatsapp') invalidateWhatsAppPreview(); });
});
syncPushChannelCards();

document.getElementById('pushTargetScope')?.addEventListener('change', () => { syncPushAudience(); invalidateWhatsAppPreview(); });
document.getElementById('pushGroupSearch')?.addEventListener('input', renderGroups);
document.getElementById('pushMemberSearch')?.addEventListener('input', renderMembers);
document.getElementById('selectAllPushGroups')?.addEventListener('click', () => {
  pushState.selectedGroups = new Set(pushState.groups.filter(g => String(g.status || 'active') === 'active').map(g => Number(g.id)));
  renderGroups();
  invalidateWhatsAppPreview();
});
document.getElementById('clearPushGroups')?.addEventListener('click', () => {
  pushState.selectedGroups = new Set();
  renderGroups();
  invalidateWhatsAppPreview();
});
document.getElementById('selectAllPushMembers')?.addEventListener('click', () => {
  pushState.selectedMembers = new Set(pushState.members.map(m => Number(m.id)));
  renderMembers();
  invalidateWhatsAppPreview();
});
document.getElementById('clearPushMembers')?.addEventListener('click', () => {
  pushState.selectedMembers = new Set();
  renderMembers();
  invalidateWhatsAppPreview();
});
document.getElementById('pushGroupList')?.addEventListener('change', e => {
  const input = e.target.closest('input[type="checkbox"]');
  if (!input) return;
  const id = Number(input.value);
  if (input.checked) pushState.selectedGroups.add(id); else pushState.selectedGroups.delete(id);
  renderGroups();
  invalidateWhatsAppPreview();
});
document.getElementById('pushMemberList')?.addEventListener('change', e => {
  const input = e.target.closest('input[type="checkbox"]');
  if (!input) return;
  const id = Number(input.value);
  if (input.checked) pushState.selectedMembers.add(id); else pushState.selectedMembers.delete(id);
  renderMembers();
  invalidateWhatsAppPreview();
});

document.getElementById('pushWalkSearch')?.addEventListener('input', renderWalks);
document.getElementById('pushWalkId')?.addEventListener('change', () => {
  pushState.selectedWalkId = Number(document.getElementById('pushWalkId').value || 0);
  renderWalks();
  syncPushAudience();
  invalidateWhatsAppPreview();
});
document.getElementById('pushWalkList')?.addEventListener('change', e => {
  const input = e.target.closest('input[name="pushWalkRadio"]');
  if (!input) return;
  document.getElementById('pushWalkId').value = input.value;
  pushState.selectedWalkId = Number(input.value || 0);
  renderWalks();
  syncPushAudience();
  invalidateWhatsAppPreview();
});
document.getElementById('applyWalkPresetBtn')?.addEventListener('click', () => { applyWalkPreset(); invalidateWhatsAppPreview(); });
document.getElementById('useWalkAudienceBtn')?.addEventListener('click', () => { useWalkAudience(); invalidateWhatsAppPreview(); });
document.getElementById('pushPreset')?.addEventListener('change', () => { const hidden = document.getElementById('pushPresetId'); if (hidden) hidden.value = ''; invalidateWhatsAppPreview(); });
document.getElementById('pushAttachments')?.addEventListener('change', () => { renderAttachments(); invalidateWhatsAppPreview(); });

document.getElementById('pushSubject')?.addEventListener('input', invalidateWhatsAppPreview);
document.getElementById('testWhatsAppConnectionBtn')?.addEventListener('click', e => {
  e.preventDefault();
  e.stopPropagation();
  loadWhatsAppStatus(true);
});

document.getElementById('previewPushBtn')?.addEventListener('click', previewPush);
document.getElementById('sendPushBtn')?.addEventListener('click', sendPush);
document.getElementById('previewPushBtnBottom')?.addEventListener('click', previewPush);
document.getElementById('sendPushBtnBottom')?.addEventListener('click', sendPush);

bindPushHistoryEvents();
initRichNotificationEditor();
loadPushCenter();
