let allMembers = [];
let allMemberGroups = [];
let allSystemUsers = [];
let memberSystemRoles = [];
let memberPermissionCatalog = [];
let selectedMemberPermissions = new Set();
let selectedMemberGroups = new Set();
let selectedBulkMemberIds = new Set();


function roleLabel(role) {
  return String(role || 'member').replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
}


function permissionLabel(key) {
  return String(key || '').replace(/[._-]/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
}

function roleDefaults(roleId) {
  const role = (memberSystemRoles || []).find(r => Number(r.id) === Number(roleId));
  return role?.default_permissions || [];
}

function renderMemberSystemRoles() {
  const select = document.getElementById('memberSystemRoleId');
  if (!select) return;
  const current = select.value;
  select.innerHTML = '<option value="">Choose role</option>' + (memberSystemRoles || []).map(r => `<option value="${Number(r.id)}">${Pyrk.esc(roleLabel(r.name))}</option>`).join('');
  if (current) select.value = current;
}

function updateMemberPrivilegeVisibility() {
  const enabled = !!document.getElementById('memberSystemAccessEnabled')?.checked;
  ['memberSystemRoleRow','memberPermissionTools','memberPermissionsList'].forEach(id => {
    const el = document.getElementById(id);
    if (el) el.hidden = !enabled;
  });
  renderMemberPermissions();
}

function renderMemberPermissions() {
  const list = document.getElementById('memberPermissionsList');
  const counter = document.getElementById('memberPermissionsCounter');
  if (counter) counter.textContent = `${selectedMemberPermissions.size} permission(s) selected`;
  if (!list || list.hidden) return;

  const q = (document.getElementById('memberPermissionSearch')?.value || '').toLowerCase().trim();

  const html = (memberPermissionCatalog || []).map(group => {
    const items = (group.items || []).filter(item => {
      const hay = `${item.key || ''} ${item.label || ''} ${group.label || ''}`.toLowerCase();
      return !q || hay.includes(q);
    });
    if (!items.length) return '';

    return `<section class="member-permission-group">
      <div class="member-permission-group-title">${Pyrk.esc(group.label || group.key || 'Permissions')}</div>
      <div class="member-permission-grid">
        ${items.map(item => {
          const key = String(item.key || '');
          const checked = selectedMemberPermissions.has(key) ? 'checked' : '';
          return `<label class="member-permission-item">
            <input type="checkbox" value="${Pyrk.esc(key)}" ${checked}>
            <span><strong>${Pyrk.esc(item.label || permissionLabel(key))}</strong><small>${Pyrk.esc(key)}</small></span>
          </label>`;
        }).join('')}
      </div>
    </section>`;
  }).join('');

  list.innerHTML = html || '<p class="muted">No permissions found.</p>';
}

function setMemberPrivilegesFromRoleDefaults() {
  const roleId = document.getElementById('memberSystemRoleId')?.value || '';
  selectedMemberPermissions = new Set(roleDefaults(roleId));
  renderMemberPermissions();
}

function setMemberSystemPrivilegeForm(member = {}) {
  renderMemberSystemRoles();

  const enabled = Number(member.is_system_user || 0) === 1 && String(member.role_name || '') !== 'member';
  const toggle = document.getElementById('memberSystemAccessEnabled');
  const roleSelect = document.getElementById('memberSystemRoleId');

  if (toggle) toggle.checked = enabled;
  if (roleSelect) roleSelect.value = enabled ? String(member.role_id || '') : '';

  selectedMemberPermissions = new Set(enabled ? (member.permissions || roleDefaults(member.role_id)) : []);
  updateMemberPrivilegeVisibility();
}

function resetMemberSystemPrivilegeForm() {
  const toggle = document.getElementById('memberSystemAccessEnabled');
  if (toggle) toggle.checked = false;
  const roleSelect = document.getElementById('memberSystemRoleId');
  if (roleSelect) roleSelect.value = '';
  selectedMemberPermissions = new Set();
  updateMemberPrivilegeVisibility();
}

function appendMemberPrivilegeData(fd) {
  if (!window.PYRK_CAN_MANAGE_USER_PRIVILEGES) return;

  const enabled = !!document.getElementById('memberSystemAccessEnabled')?.checked;
  fd.set('system_access_enabled', enabled ? '1' : '0');

  if (enabled) {
    const roleId = document.getElementById('memberSystemRoleId')?.value || '';
    if (!roleId) {
      throw new Error('Choose the system role for this member.');
    }
    fd.set('system_role_id', roleId);
    fd.set('permissions', JSON.stringify(Array.from(selectedMemberPermissions)));
  } else {
    fd.set('system_role_id', '');
    fd.set('permissions', JSON.stringify([]));
  }
}


function systemUserBadge(member) {
  if (!Number(member.is_system_user || 0)) return '';
  return `<span class="pill role-pill system-role-pill">System user · ${Pyrk.esc(roleLabel(member.role_name))}</span>`;
}

function systemUserOptionLabel(user) {
  if (!user) return 'Create new member login / keep current member login';
  return `${user.full_name || 'System user'} · ${user.email || ''} · ${roleLabel(user.role_name)}`;
}

function setSystemUserLinkValue(value, label = '') {
  const hidden = document.getElementById('linkSystemUserId');
  const labelEl = document.getElementById('linkSystemUserLabel');
  if (hidden) hidden.value = value ? String(value) : '';
  if (labelEl) labelEl.textContent = label || 'Create new member login / keep current member login';
}

function closeSystemUserSearchMenu() {
  const menu = document.getElementById('linkSystemUserMenu');
  const toggle = document.getElementById('linkSystemUserToggle');
  if (menu) menu.hidden = true;
  if (toggle) toggle.setAttribute('aria-expanded', 'false');
}

function openSystemUserSearchMenu() {
  const menu = document.getElementById('linkSystemUserMenu');
  const toggle = document.getElementById('linkSystemUserToggle');
  const search = document.getElementById('linkSystemUserSearch');
  if (!menu) return;
  renderSystemUserOptions(search?.value || '');
  menu.hidden = false;
  if (toggle) toggle.setAttribute('aria-expanded', 'true');
  setTimeout(() => search?.focus(), 30);
}

function renderSystemUserOptions(query = '') {
  const list = document.getElementById('linkSystemUserOptions');
  if (!list) return;

  const q = String(query || '').trim().toLowerCase();
  const rows = (allSystemUsers || []).filter(u => {
    const hay = `${u.full_name || ''} ${u.email || ''} ${u.mobile || ''} ${u.role_name || ''}`.toLowerCase();
    return !q || hay.includes(q);
  });

  const current = Number(document.getElementById('linkSystemUserId')?.value || 0);

  list.innerHTML = `
    <button class="system-user-option ${!current ? 'is-selected' : ''}" type="button" data-system-user-id="">
      <span class="system-user-option-avatar">M</span>
      <span><strong>Create new member login / keep current member login</strong><small>No system role link</small></span>
    </button>
  ` + rows.map(u => {
    const id = Number(u.id);
    const disabled = Number(u.has_member_profile || 0) === 1 && id !== current;
    const selected = id === current;
    return `<button class="system-user-option ${selected ? 'is-selected' : ''} ${disabled ? 'is-disabled' : ''}" type="button" data-system-user-id="${id}" ${disabled ? 'disabled' : ''}>
      <span class="system-user-option-avatar">${Pyrk.esc(initials(u.full_name || 'U'))}</span>
      <span>
        <strong>${Pyrk.esc(u.full_name || 'System user')}</strong>
        <small>${Pyrk.esc(u.email || '')} · ${Pyrk.esc(roleLabel(u.role_name))}${disabled ? ' · already linked' : ''}</small>
      </span>
    </button>`;
  }).join('');

  if (!rows.length && q) {
    list.innerHTML += '<p class="muted system-user-no-results">No system user found.</p>';
  }
}

function fillSystemUserSelect() {
  renderSystemUserOptions('');
  const hidden = document.getElementById('linkSystemUserId');
  const id = Number(hidden?.value || 0);
  const user = (allSystemUsers || []).find(u => Number(u.id) === id) || null;
  setSystemUserLinkValue(id || '', systemUserOptionLabel(user));
}

function selectedSystemUser() {
  const id = Number(document.getElementById('linkSystemUserId')?.value || 0);
  return (allSystemUsers || []).find(u => Number(u.id) === id) || null;
}

function applySelectedSystemUserToForm() {
  const user = selectedSystemUser();
  const roleInput = document.getElementById('linkedSystemUserRole');
  const password = document.getElementById('password');
  const email = document.getElementById('email');

  setSystemUserLinkValue(user ? user.id : '', systemUserOptionLabel(user));

  if (!user) {
    if (roleInput) roleInput.value = 'New member account';
    if (password) {
      password.disabled = false;
      password.placeholder = 'Default password is password';
    }
    if (email) email.readOnly = false;
    return;
  }

  if (roleInput) roleInput.value = roleLabel(user.role_name);
  document.getElementById('firstName').value = personFirstName(user);
  document.getElementById('lastName').value = personLastName(user);
  syncPersonNameHidden('firstName', 'lastName', 'fullName');
  if (email) {
    email.value = user.email || '';
    email.readOnly = true;
  }
  setPhoneInputs(user.mobile || '', 'mobile', 'mobileNumber');

  if (password) {
    password.value = '';
    password.disabled = true;
    password.placeholder = 'Existing system user password stays unchanged';
  }

  const preview = document.getElementById('memberAvatarPreview');
  if (preview && user.profile_photo_path) {
    preview.outerHTML = `<img class="avatar-preview xl" id="memberAvatarPreview" src="${Pyrk.esc(publicAsset(user.profile_photo_path))}" alt="Preview">`;
  } else if (preview) {
    preview.outerHTML = `<div class="avatar-preview xl" id="memberAvatarPreview">${Pyrk.esc(initials(personDisplayName(user, 'User')))}</div>`;
  }
}

function lockSystemUserLinkForEdit(member) {
  const select = document.getElementById('linkSystemUserId');
  const roleInput = document.getElementById('linkedSystemUserRole');
  const password = document.getElementById('password');
  const email = document.getElementById('email');

  if (!select) return;

  if (Number(member.is_system_user || 0) === 1) {
    setSystemUserLinkValue(member.id, `Linked to ${personDisplayName(member, 'System user')}`);
    const toggle = document.getElementById('linkSystemUserToggle');
    if (toggle) toggle.disabled = true;
    closeSystemUserSearchMenu();
    if (roleInput) roleInput.value = roleLabel(member.role_name);
    if (password) {
      password.disabled = true;
      password.placeholder = 'Manage password from System Users';
    }
    if (email) email.readOnly = true;
  } else {
    setSystemUserLinkValue('', 'Create new member login / keep current member login');
    const toggle = document.getElementById('linkSystemUserToggle');
    if (toggle) toggle.disabled = false;
    renderSystemUserOptions('');
    if (roleInput) roleInput.value = 'Current member login';
    if (password) {
      password.disabled = false;
      password.placeholder = 'Leave empty to keep current password';
    }
    if (email) email.readOnly = false;
  }
}


// Robust date helpers. This keeps profile popups working even if the browser cached an older api.js.
if (!window.Pyrk) window.Pyrk = {};
if (typeof Pyrk.esc !== 'function') {
  Pyrk.esc = value => String(value ?? '').replace(/[&<>'"]/g, c => ({'&':'&amp;', '<':'&lt;', '>':'&gt;', "'":'&#39;', '"':'&quot;'}[c]));
}
if (typeof Pyrk.formatDate !== 'function') {
  Pyrk.formatDate = value => {
    if (!value) return '—';
    const s = String(value).trim();
    const m = s.match(/^(\d{4})-(\d{2})-(\d{2})/);
    if (m) return `${m[3]}/${m[2]}/${m[1]}`;
    const dmy = s.match(/^(\d{2})\/(\d{2})\/(\d{4})/);
    if (dmy) return `${dmy[1]}/${dmy[2]}/${dmy[3]}`;
    return s;
  };
}
if (typeof Pyrk.formatDateTime !== 'function') {
  Pyrk.formatDateTime = value => {
    if (!value) return '—';
    const s = String(value).trim().replace('T', ' ');
    const date = Pyrk.formatDate(s.slice(0, 10));
    const time = s.length >= 16 ? s.slice(11, 16) : '';
    return time ? `${date} ${time}` : date;
  };
}
if (typeof Pyrk.isoFromDmy !== 'function') {
  Pyrk.isoFromDmy = value => {
    const s = String(value || '').trim();
    const m = s.match(/^(\d{2})\/(\d{2})\/(\d{4})$/);
    return m ? `${m[3]}-${m[2]}-${m[1]}` : s;
  };
}
if (typeof Pyrk.dmyFromIso !== 'function') {
  Pyrk.dmyFromIso = value => Pyrk.formatDate(value);
}

const PHONE_COUNTRIES = [
  {name:'Lebanon', code:'+961', flag:'🇱🇧'},
  {name:'United Arab Emirates', code:'+971', flag:'🇦🇪'},
  {name:'Saudi Arabia', code:'+966', flag:'🇸🇦'},
  {name:'Qatar', code:'+974', flag:'🇶🇦'},
  {name:'Kuwait', code:'+965', flag:'🇰🇼'},
  {name:'Bahrain', code:'+973', flag:'🇧🇭'},
  {name:'Oman', code:'+968', flag:'🇴🇲'},
  {name:'Jordan', code:'+962', flag:'🇯🇴'},
  {name:'Egypt', code:'+20', flag:'🇪🇬'},
  {name:'Turkey', code:'+90', flag:'🇹🇷'},
  {name:'United States', code:'+1', flag:'🇺🇸'},
  {name:'Canada', code:'+1', flag:'🇨🇦'},
  {name:'United Kingdom', code:'+44', flag:'🇬🇧'},
  {name:'France', code:'+33', flag:'🇫🇷'},
  {name:'Germany', code:'+49', flag:'🇩🇪'},
  {name:'Australia', code:'+61', flag:'🇦🇺'}
];

function countryLabel(country) {
  return `${country.flag || ''} ${country.name} ${country.code}`.trim();
}

function countryByCode(code) {
  return PHONE_COUNTRIES.find(c => c.code === code) || PHONE_COUNTRIES[0];
}

function countryByNameAndCode(name, code) {
  return PHONE_COUNTRIES.find(c => c.name === name && c.code === code) || countryByCode(code);
}

function phoneWidget(widget) {
  return document.querySelector(`[data-phone-widget="${widget}"]`);
}

function selectCountry(widget, code = '+961', name = '') {
  const root = phoneWidget(widget);
  if (!root) return;
  const country = name ? countryByNameAndCode(name, code) : countryByCode(code);
  root.dataset.code = country.code;
  root.dataset.name = country.name;
  const label = document.getElementById(`${widget}CountryLabel`);
  if (label) label.textContent = countryLabel(country);
  const search = document.querySelector(`[data-country-search="${widget}"]`);
  if (search) search.value = '';
  renderCountryOptions(widget, '');
  syncPhoneHidden();
}

function getCountryCode(widget) {
  return phoneWidget(widget)?.dataset.code || '+961';
}

function getCountryName(widget) {
  return phoneWidget(widget)?.dataset.name || 'Lebanon';
}

function renderCountryOptions(widget, query = '') {
  const box = document.querySelector(`[data-country-options="${widget}"]`);
  if (!box) return;
  const q = String(query || '').trim().toLowerCase();
  const selectedCode = getCountryCode(widget);
  const selectedName = getCountryName(widget);
  const rows = PHONE_COUNTRIES.filter(c => !q || `${c.name} ${c.code}`.toLowerCase().includes(q));
  box.innerHTML = rows.map(c => `
    <button class="country-option-pro ${c.code === selectedCode && c.name === selectedName ? 'is-selected' : ''}" type="button" data-country-code="${Pyrk.esc(c.code)}" data-country-name="${Pyrk.esc(c.name)}" role="option">
      <span>${Pyrk.esc(c.flag)} ${Pyrk.esc(c.name)}</span>
      <strong>${Pyrk.esc(c.code)}</strong>
    </button>`).join('') || '<p class="muted country-empty">No country found.</p>';
}

function openCountryDropdown(widget) {
  document.querySelectorAll('.country-dropdown-pro').forEach(menu => menu.hidden = true);
  document.querySelectorAll('[data-country-button]').forEach(btn => btn.setAttribute('aria-expanded', 'false'));
  const menu = document.querySelector(`[data-country-menu="${widget}"]`);
  const btn = document.querySelector(`[data-country-button="${widget}"]`);
  if (!menu) return;
  renderCountryOptions(widget, '');
  menu.hidden = false;
  if (btn) btn.setAttribute('aria-expanded', 'true');
  setTimeout(() => document.querySelector(`[data-country-search="${widget}"]`)?.focus(), 30);
}

function closeCountryDropdowns() {
  document.querySelectorAll('.country-dropdown-pro').forEach(menu => menu.hidden = true);
  document.querySelectorAll('[data-country-button]').forEach(btn => btn.setAttribute('aria-expanded', 'false'));
}

function splitPhone(value, fallbackCode = '+961') {
  const raw = String(value || '').trim();
  if (!raw) return {code: fallbackCode, name: countryByCode(fallbackCode).name, number: ''};
  const compact = raw.replace(/[^\d+]/g, '');
  const codes = [...new Set(PHONE_COUNTRIES.map(c => c.code))].sort((a, b) => b.length - a.length);
  if (compact.startsWith('+')) {
    const code = codes.find(c => compact.startsWith(c)) || fallbackCode;
    return {code, name: countryByCode(code).name, number: compact.slice(code.length).replace(/^0+/, '')};
  }
  return {code: fallbackCode, name: countryByCode(fallbackCode).name, number: compact.replace(/^0+/, '')};
}

function setPhoneInputs(fullValue, widget, numberInputId, fallbackCode = '+961') {
  const parts = splitPhone(fullValue, fallbackCode);
  selectCountry(widget, parts.code, parts.name);
  const number = document.getElementById(numberInputId);
  if (number) number.value = parts.number;
  syncPhoneHidden();
}

function syncPhoneHidden() {
  const mobileCode = getCountryCode('mobile');
  const mobileNumber = String(document.getElementById('mobileNumber')?.value || '').replace(/[^\d]/g, '').replace(/^0+/, '');
  const mobile = document.getElementById('mobile');
  if (mobile) mobile.value = mobileNumber ? `${mobileCode}${mobileNumber}` : '';

  const emergencyCode = getCountryCode('emergency') || mobileCode;
  const emergencyNumber = String(document.getElementById('emergencyMobileNumber')?.value || '').replace(/[^\d]/g, '').replace(/^0+/, '');
  const emergency = document.getElementById('emergencyContactMobile');
  if (emergency) emergency.value = emergencyNumber ? `${emergencyCode}${emergencyNumber}` : '';
}

function maskDmyDateInput(input) {
  if (!input || input.dataset.dmyReady === '1') return;
  input.dataset.dmyReady = '1';
  input.addEventListener('input', () => {
    let v = input.value.replace(/\D/g, '').slice(0, 8);
    if (v.length >= 5) v = v.slice(0, 2) + '/' + v.slice(2, 4) + '/' + v.slice(4);
    else if (v.length >= 3) v = v.slice(0, 2) + '/' + v.slice(2);
    input.value = v;
  });
}

function setMemberPasswordVisible(isVisible) {
  const input = document.getElementById('password');
  const btn = document.getElementById('toggleMemberPassword');
  if (!input || !btn) return;
  input.type = isVisible ? 'text' : 'password';
  btn.classList.toggle('is-visible', isVisible);
  btn.setAttribute('aria-label', isVisible ? 'Hide password' : 'Show password');
  btn.title = isVisible ? 'Hide password' : 'Show password';
}

function profileField(label, value) {
  return `<div class="profile-field-row"><span>${Pyrk.esc(label)}</span><strong>${value && String(value).trim() ? Pyrk.esc(value) : '—'}</strong></div>`;
}

function profileFieldHtml(label, html) {
  return `<div class="profile-field-row"><span>${Pyrk.esc(label)}</span><strong>${html || '—'}</strong></div>`;
}




function splitPersonName(fullName) {
  const parts = String(fullName || '').trim().replace(/\s+/g, ' ').split(' ').filter(Boolean);
  if (!parts.length) return { first_name: '', last_name: '' };
  return { first_name: parts.shift() || '', last_name: parts.join(' ') };
}

function personFirstName(person) {
  const first = String(person?.first_name || '').trim();
  if (first) return first;
  return splitPersonName(person?.full_name || '').first_name;
}

function personLastName(person) {
  const last = String(person?.last_name || '').trim();
  if (last) return last;
  return splitPersonName(person?.full_name || '').last_name;
}

function personDisplayName(person, fallback = 'User') {
  const full = `${personFirstName(person)} ${personLastName(person)}`.trim();
  return full || String(person?.display_name || person?.full_name || fallback).trim() || fallback;
}

function syncPersonNameHidden(firstId, lastId, fullId) {
  const first = document.getElementById(firstId);
  const last = document.getElementById(lastId);
  const full = document.getElementById(fullId);
  if (!first || !last || !full) return '';
  full.value = `${first.value || ''} ${last.value || ''}`.trim().replace(/\s+/g, ' ');
  return full.value;
}


function publicAsset(path) {
  if (!path) return '';
  if (/^https?:\/\//.test(path)) return path;
  return (window.PYRK_PUBLIC_BASE || '../') + String(path).replace(/^\/+/, '');
}

function initials(name) {
  return String(name || 'M').trim().split(/\s+/).slice(0, 2).map(p => p[0] || '').join('').toUpperCase() || 'M';
}

function avatarHtml(person, sizeClass = '') {
  if (person && person.profile_photo_path) {
    return `<img class="avatar-img ${sizeClass}" src="${Pyrk.esc(publicAsset(person.profile_photo_path))}" alt="${Pyrk.esc(personDisplayName(person, 'Member'))}">`;
  }
  return `<div class="avatar ${sizeClass}">${Pyrk.esc(initials(person ? personDisplayName(person, 'Member') : ''))}</div>`;
}

function emptyText(value, fallback = '—') {
  const str = String(value || '').trim();
  return str ? Pyrk.esc(str) : fallback;
}

function formatDate(value) { return Pyrk.formatDate(value); }

function formatTime(value) {
  if (!value) return '';
  return String(value).slice(0, 5);
}

function statusPill(status) {
  const s = String(status || 'unknown');
  const cls = ['active', 'registered', 'approved', 'finished', 'winner', 'open'].includes(s) ? 'pill-green' : (['blocked', 'rejected', 'cancelled'].includes(s) ? 'pill-red' : 'pill-muted');
  return `<span class="pill ${cls}">${Pyrk.esc(s.replace(/_/g, ' '))}</span>`;
}


function memberSecurityLine(m) {
  const failed = Number(m.failed_login_count || 0);
  const locked = m.locked_until && new Date(String(m.locked_until).replace(' ', 'T')).getTime() > Date.now();
  const bits = [];
  if (locked) bits.push(`<span class="pill pill-red">Locked</span>`);
  if (failed > 0) bits.push(`<span class="pill pill-muted">${failed} failed</span>`);
  if (m.last_login_ip) bits.push(`<small>IP ${Pyrk.esc(m.last_login_ip)}</small>`);
  return bits.length ? `<div class="security-mini">${bits.join('')}</div>` : '';
}

function computeMemberStats() {
  const members = allMembers.length;
  const active = allMembers.filter(m => m.status === 'active').length;
  const km = allMembers.reduce((sum, m) => sum + Number(m.total_kilometers || 0), 0);
  const points = allMembers.reduce((sum, m) => sum + Number(m.loyalty_points || 0), 0);
  document.getElementById('totalMembers').textContent = members;
  document.getElementById('totalActiveMembers').textContent = active;
  document.getElementById('totalMemberKm').textContent = km.toFixed(1);
  document.getElementById('totalMemberPoints').textContent = points;
}

function filteredMembers() {
  const q = (document.getElementById('memberSearch').value || '').toLowerCase().trim();
  const status = document.getElementById('memberStatusFilter').value;
  return allMembers.filter(m => {
    const hay = `${personDisplayName(m, '')} ${m.first_name || ''} ${m.last_name || ''} ${m.email || ''} ${m.mobile || ''} ${m.emergency_contact_name || ''} ${m.emergency_contact_mobile || ''} ${m.medical_conditions || ''}`.toLowerCase();
    return (!q || hay.includes(q)) && (!status || m.status === status);
  });
}

function bulkEligibleMemberRows(rows = filteredMembers()) {
  return rows.filter(m => String(m.status || '') === 'inactive');
}

function pruneBulkSelection() {
  const availableInactive = new Set(allMembers.filter(m => String(m.status || '') === 'inactive').map(m => Number(m.id)));
  selectedBulkMemberIds = new Set(Array.from(selectedBulkMemberIds).filter(id => availableInactive.has(Number(id))));
}

function updateBulkStatusControls(rows = filteredMembers()) {
  pruneBulkSelection();
  const canEdit = !!window.PYRK_CAN_EDIT_MEMBERS;
  const bar = document.getElementById('memberBulkStatusBar');
  if (bar) bar.hidden = !canEdit;
  if (!canEdit) return;

  const eligibleShown = bulkEligibleMemberRows(rows).map(m => Number(m.id));
  const shownSet = new Set(eligibleShown);
  const selectedShownCount = Array.from(selectedBulkMemberIds).filter(id => shownSet.has(Number(id))).length;
  const totalSelected = selectedBulkMemberIds.size;

  const counter = document.getElementById('memberBulkCounter');
  if (counter) counter.textContent = `${totalSelected} selected`;

  const activateBtn = document.getElementById('memberBulkActivate');
  if (activateBtn) activateBtn.disabled = totalSelected === 0;

  const selectShown = document.getElementById('memberBulkSelectShown');
  if (selectShown) {
    selectShown.checked = eligibleShown.length > 0 && selectedShownCount === eligibleShown.length;
    selectShown.indeterminate = selectedShownCount > 0 && selectedShownCount < eligibleShown.length;
    selectShown.disabled = eligibleShown.length === 0;
  }
}

function setBulkMemberSelected(id, selected) {
  const member = allMembers.find(m => Number(m.id) === Number(id));
  if (!member || String(member.status || '') !== 'inactive') return;
  if (selected) selectedBulkMemberIds.add(Number(id));
  else selectedBulkMemberIds.delete(Number(id));
  updateBulkStatusControls();
}

window.toggleBulkMember = function toggleBulkMember(id, checked) {
  setBulkMemberSelected(id, checked);
};

function setShownInactiveSelection(selected) {
  const eligible = bulkEligibleMemberRows();
  eligible.forEach(member => {
    if (selected) selectedBulkMemberIds.add(Number(member.id));
    else selectedBulkMemberIds.delete(Number(member.id));
  });
  renderMembers();
}

async function bulkActivateSelectedMembers() {
  pruneBulkSelection();
  const ids = Array.from(selectedBulkMemberIds);
  if (!ids.length) {
    alert('Select at least one inactive member first.');
    return;
  }
  const confirmed = confirm(`Activate ${ids.length} inactive member(s)?

Blocked members will not be changed.`);
  if (!confirmed) return;
  const res = await Pyrk.post('members.php', {action:'bulk_activate_members', member_ids: ids});
  alert(res.message || (res.ok ? 'Members activated.' : 'Could not activate members.'));
  if (res.ok) {
    selectedBulkMemberIds.clear();
    await loadMembers();
  }
}

function renderMemberTable(rows) {
  const canEdit = !!window.PYRK_CAN_EDIT_MEMBERS;
  const canDelete = !!window.PYRK_CAN_DELETE_MEMBERS;
  const body = document.getElementById('membersTableBody');

  body.innerHTML = rows.map(m => {
    const registrationCount = Number(m.registrations_count || 0);
    const securityShort = m.locked_until ? 'Locked' : (m.failed_login_count ? `${Number(m.failed_login_count)} failed` : '');
    const profileHint = [
      m.emergency_contact_name ? `Emergency: ${m.emergency_contact_name}` : '',
      m.medical_conditions ? 'Medical notes' : '',
      Number(m.photos_count || 0) ? `${Number(m.photos_count || 0)} photos` : ''
    ].filter(Boolean).join(' · ');

    return `
      <tr class="clickable-row compact-member-row" onclick="openMemberProfile(${m.id})">
        ${canEdit ? `<td class="member-select-cell" onclick="event.stopPropagation()"><label class="member-row-check" title="Select inactive member"><input type="checkbox" ${String(m.status || '') === 'inactive' ? '' : 'disabled'} ${selectedBulkMemberIds.has(Number(m.id)) ? 'checked' : ''} onchange="toggleBulkMember(${m.id}, this.checked)"><span class="sr-only">Select member</span></label></td>` : ''}
        <td class="member-main-cell">
          <div class="identity-cell compact-identity">
            ${avatarHtml(m, 'avatar-sm')}
            <div>
              <strong>${Pyrk.esc(personDisplayName(m, 'Member'))}</strong>
              ${systemUserBadge(m)}
              <small>ID #${m.id}${m.qr_token ? ' · ' + Pyrk.esc(m.qr_token) : ''}</small>
              ${profileHint ? `<small class="desktop-muted">${Pyrk.esc(profileHint)}</small>` : ''}
            </div>
          </div>
        </td>
        <td class="member-contact-cell">
          <strong>${emptyText(m.email)}</strong>
          <small>${emptyText(m.mobile, 'No mobile')}</small>
          <small class="mobile-extra">${m.age ? `${m.age} yrs` : 'Age —'} · ${emptyText(m.gender ? String(m.gender).replace(/_/g, ' ') : '')}</small>
        </td>
        <td class="member-activity-cell">
          <strong>${Number(m.total_walks || 0)} walks · ${Number(m.total_kilometers || 0).toFixed(1)} KM</strong>
          <small>${registrationCount} registrations · ${Number(m.loyalty_points || 0)} pts</small>
        </td>
        <td class="member-status-cell">
          ${statusPill(m.status)}
          ${securityShort ? `<small>${Pyrk.esc(securityShort)}</small>` : ''}
        </td>
        <td class="table-actions members-table-actions" onclick="event.stopPropagation()">
          <button class="btn btn-light btn-small icon-action" type="button" title="Profile" aria-label="Profile" onclick="openMemberProfile(${m.id})">Profile</button>
          ${canEdit ? `<button class="btn btn-small icon-action" type="button" title="Edit" aria-label="Edit" onclick="editMember(${m.id})">Edit</button>` : ''}
          ${canEdit ? (m.status === 'blocked'
            ? `<button class="btn btn-small icon-action" type="button" title="Unblock" aria-label="Unblock" onclick="unblockMember(${m.id})">Unblock</button>`
            : `<button class="btn btn-danger btn-small icon-action" type="button" title="Block" aria-label="Block" onclick="blockMember(${m.id})">Block</button>`) : ''}
          ${canEdit && m.locked_until ? `<button class="btn btn-light btn-small icon-action" type="button" title="Reset lock" aria-label="Reset lock" onclick="resetMemberLock(${m.id})">Reset</button>` : ''}
          <a class="btn btn-light btn-small icon-action" title="Logins" aria-label="Logins" href="security.php?user_id=${m.id}">Logins</a>
          ${canDelete ? `<button class="btn btn-danger btn-small icon-action" type="button" title="Delete" aria-label="Delete" onclick="deleteMember(${m.id}, '${Pyrk.esc(m.full_name || 'member').replace(/'/g, '&#39;')}')">Delete</button>` : ''}
        </td>
      </tr>`;
  }).join('') || `<tr><td colspan="${canEdit ? 6 : 5}" class="muted">No members match your filters.</td></tr>`;
  updateBulkStatusControls(rows);
}

function renderMemberCards(rows) {
  const canEdit = !!window.PYRK_CAN_EDIT_MEMBERS;
  const html = rows.map(m => {
    const medical = m.medical_conditions ? `<p class="member-note">${Pyrk.esc(m.medical_conditions)}</p>` : '';
    return `<article class="member-card enterprise-member-card clickable-card" onclick="openMemberProfile(${m.id})">
      <div class="member-card-head">
        ${avatarHtml(m)}
        <div><h3>${Pyrk.esc(m.full_name)}</h3><p>${Pyrk.esc(m.email)}</p></div>
        ${statusPill(m.status)}
        ${canEdit ? `<label class="member-card-check" onclick="event.stopPropagation()"><input type="checkbox" ${String(m.status || '') === 'inactive' ? '' : 'disabled'} ${selectedBulkMemberIds.has(Number(m.id)) ? 'checked' : ''} onchange="toggleBulkMember(${m.id}, this.checked)"><span>Select</span></label>` : ''}
      </div>
      <div class="member-meta">
        <span>${Pyrk.esc(m.mobile || 'No mobile')}</span>
        <span>${m.age ? `${m.age} yrs` : 'Age not set'}</span>
        <span>${Pyrk.esc((m.gender || 'Gender not set').replace(/_/g, ' '))}</span>
      </div>
      <div class="mini-metrics four-metrics">
        <div><strong>${Number(m.total_walks || 0)}</strong><span>Walks</span></div>
        <div><strong>${Number(m.total_kilometers || 0).toFixed(1)}</strong><span>KM</span></div>
        <div><strong>${Number(m.loyalty_points || 0)}</strong><span>Points</span></div>
        <div><strong>${Number(m.photos_count || 0)}</strong><span>Photos</span></div>
      </div>
      <p class="muted small"><strong>Emergency:</strong> ${Pyrk.esc(m.emergency_contact_name || '')} ${Pyrk.esc(m.emergency_contact_mobile || 'Not set')}</p>
      ${medical}
      ${memberSecurityLine(m)}
      <div class="inline-controls" onclick="event.stopPropagation()">
        <button class="btn btn-light btn-small" type="button" onclick="openMemberProfile(${m.id})">Open profile</button>
        ${canEdit ? `<button class="btn btn-small" type="button" onclick="editMember(${m.id})">Edit member</button>` : ''}
        ${canEdit ? (m.status === 'blocked' ? `<button class="btn btn-small" type="button" onclick="unblockMember(${m.id})">Unblock</button>` : `<button class="btn btn-danger btn-small" type="button" onclick="blockMember(${m.id})">Block</button>`) : ''}
      </div>
    </article>`;
  }).join('');
  document.getElementById('membersGrid').innerHTML = html || '<p class="muted">No members match your filters.</p>';
  updateBulkStatusControls(rows);
}

function renderMembers() {
  const rows = filteredMembers();
  const view = document.getElementById('memberViewMode').value;
  const tableWrap = document.getElementById('membersTableWrap');
  const grid = document.getElementById('membersGrid');
  if (view === 'cards') {
    tableWrap.hidden = true;
    grid.hidden = false;
    renderMemberCards(rows);
  } else {
    grid.hidden = true;
    tableWrap.hidden = false;
    renderMemberTable(rows);
  }
}

function openModal(id) {
  const modal = document.getElementById(id);
  if (!modal) return;
  modal.hidden = false;
  document.body.classList.add('modal-open');
}

function closeModal(id) {
  const modal = document.getElementById(id);
  if (!modal) return;
  modal.hidden = true;
  if (!document.querySelector('.modal-backdrop:not([hidden])')) document.body.classList.remove('modal-open');
}


function groupSearchText(group) {
  return `${group.group_name || ''} ${group.description || ''} ${group.status || ''}`.toLowerCase();
}

function renderMemberGroupsEditor() {
  const list = document.getElementById('memberGroupsChecklist');
  const selectedBox = document.getElementById('memberGroupsSelected');
  const search = document.getElementById('memberGroupSearch');
  if (!list || !selectedBox) return;

  const query = String(search?.value || '').toLowerCase().trim();
  const groups = (allMemberGroups || []).filter(group => !query || groupSearchText(group).includes(query));

  const selectedGroups = (allMemberGroups || []).filter(group => selectedMemberGroups.has(Number(group.id)));
  selectedBox.innerHTML = selectedGroups.length
    ? selectedGroups.map(group => `
      <button class="member-group-chip" type="button" data-remove-group="${Number(group.id)}" title="Remove group">
        <span>👥 ${Pyrk.esc(group.group_name || 'Group')}</span><b>×</b>
      </button>`).join('')
    : '<span class="typeahead-placeholder">No groups selected yet.</span>';

  list.innerHTML = groups.length ? groups.map(group => {
    const id = Number(group.id);
    const selected = selectedMemberGroups.has(id);
    return `<label class="member-group-option ${selected ? 'is-selected' : ''}">
      <input type="checkbox" value="${id}" ${selected ? 'checked' : ''}>
      <span>
        <strong>${Pyrk.esc(group.group_name || 'Unnamed group')}</strong>
        <small>${Number(group.member_count || 0)} members${group.description ? ' · ' + Pyrk.esc(group.description) : ''}</small>
      </span>
      <em>${selected ? 'Selected' : 'Add'}</em>
    </label>`;
  }).join('') : '<div class="member-groups-empty"><strong>No groups found</strong><small>Create groups from People → Member groups.</small></div>';

  selectedBox.querySelectorAll('[data-remove-group]').forEach(btn => {
    btn.addEventListener('click', () => {
      selectedMemberGroups.delete(Number(btn.dataset.removeGroup));
      renderMemberGroupsEditor();
    });
  });

  list.querySelectorAll('input[type="checkbox"]').forEach(input => {
    input.addEventListener('change', () => {
      const id = Number(input.value);
      if (input.checked) selectedMemberGroups.add(id);
      else selectedMemberGroups.delete(id);
      renderMemberGroupsEditor();
    });
  });
}

function setMemberGroups(groups = [], available = null) {
  if (Array.isArray(available)) {
    allMemberGroups = available;
  }
  selectedMemberGroups = new Set((groups || []).map(group => Number(group.id || group)).filter(Boolean));
  renderMemberGroupsEditor();
}

function appendSelectedGroupsToFormData(fd) {
  fd.delete('group_ids[]');
  fd.delete('group_ids');
  Array.from(selectedMemberGroups).forEach(id => fd.append('group_ids[]', id));
}


function resetMemberForm() {
  const form = document.getElementById('memberForm');
  if (!form) return;
  form.reset();
  syncPersonNameHidden('firstName', 'lastName', 'fullName');
  document.getElementById('memberId').value = '';
  document.getElementById('memberFormTitle').textContent = 'Create member';
  document.getElementById('memberCanEditOwnProfile').value = '1';
  document.getElementById('password').placeholder = 'Default password is password';
  setMemberPasswordVisible(false);
  setPhoneInputs('', 'mobile', 'mobileNumber');
  setPhoneInputs('', 'emergency', 'emergencyMobileNumber');
  resetMemberSystemPrivilegeForm();
  const emailInput = document.getElementById('email');
  if (emailInput) emailInput.readOnly = false;
  const picker = document.getElementById('dateOfBirthPicker');
  if (picker) picker.value = '';
  document.getElementById('memberAvatarPreview').outerHTML = '<div class="avatar-preview xl" id="memberAvatarPreview">M</div>';
  setMemberGroups([], allMemberGroups);
  document.getElementById('memberMsg').textContent = '';
}

window.openNewMember = function openNewMember() {
  resetMemberForm();
  openModal('memberFormModal');
};

window.editMember = async function editMember(id) {
  const res = await Pyrk.get('members.php', {action:'detail', id});
  if (!res.ok) { alert(res.message); return; }
  const m = res.data.member;
  memberSystemRoles = res.data.roles || memberSystemRoles || [];
  memberPermissionCatalog = res.data.permissions_catalog || memberPermissionCatalog || [];
  renderMemberSystemRoles();
  document.getElementById('memberFormTitle').textContent = 'Edit member';
  document.getElementById('memberId').value = m.id || '';
  document.getElementById('firstName').value = personFirstName(m);
  document.getElementById('lastName').value = personLastName(m);
  syncPersonNameHidden('firstName', 'lastName', 'fullName');
  document.getElementById('email').value = m.email || '';
  setPhoneInputs(m.mobile || '', 'mobile', 'mobileNumber');
  document.getElementById('status').value = m.status || 'active';
  document.getElementById('memberCanEditOwnProfile').value = Number(m.can_edit_own_profile ?? 1) === 1 ? '1' : '0';
  document.getElementById('password').value = '';
  document.getElementById('password').placeholder = 'Leave empty to keep current password';
  setMemberPasswordVisible(false);
  document.getElementById('dateOfBirth').value = m.date_of_birth ? Pyrk.dmyFromIso(m.date_of_birth) : '';
  const dobPicker = document.getElementById('dateOfBirthPicker');
  if (dobPicker) dobPicker.value = m.date_of_birth ? String(m.date_of_birth).slice(0, 10) : '';
  document.getElementById('gender').value = m.gender || '';
  document.getElementById('emergencyContactName').value = m.emergency_contact_name || '';
  setPhoneInputs(m.emergency_contact_mobile || '', 'emergency', 'emergencyMobileNumber', getCountryCode('mobile'));
  document.getElementById('medicalConditions').value = m.medical_conditions || '';
  document.getElementById('photoConsent').checked = Number(m.photo_consent || 0) === 1;
  setMemberGroups(res.data.member_groups || [], res.data.available_groups || allMemberGroups);
  setMemberSystemPrivilegeForm(m);
  const preview = document.getElementById('memberAvatarPreview');
  if (m.profile_photo_path) {
    preview.outerHTML = `<img class="avatar-preview xl" id="memberAvatarPreview" src="${Pyrk.esc(publicAsset(m.profile_photo_path))}" alt="Preview">`;
  } else {
    preview.outerHTML = `<div class="avatar-preview xl" id="memberAvatarPreview">${Pyrk.esc(initials(personDisplayName(m, 'Member')))}</div>`;
  }
  document.getElementById('memberMsg').textContent = '';
  closeModal('memberProfileModal');
  openModal('memberFormModal');
};

function renderProfileWalks(walks) {
  if (!walks || !walks.length) return '<p class="muted">No walk registrations yet.</p>';
  return `<div class="table-wrap compact-table-wrap"><table class="pro-table compact-pro-table"><thead><tr><th>Walk / route</th><th>Date</th><th>Registration</th><th>Attendance</th><th>KM</th></tr></thead><tbody>${walks.map(w => `
    <tr>
      <td><strong>${Pyrk.esc(w.walk_title)}</strong><small>${Pyrk.esc(w.route_name || '')}</small></td>
      <td>${formatDate(w.walk_date)} <small>${formatTime(w.start_time)}</small></td>
      <td>${statusPill(w.registration_status)}</td>
      <td>${w.attendance_status ? statusPill(w.attendance_status) : '<span class="muted">Not checked in</span>'}</td>
      <td><strong>${Number(w.verified_km || w.total_km || 0).toFixed(1)}</strong></td>
    </tr>`).join('')}</tbody></table></div>`;
}

function renderProfileWaivers(waivers, memberId) {
  if (!waivers || !waivers.length) {
    return `<div class="member-waiver-empty"><strong>No signed waivers yet.</strong><span>When this member signs a required walk waiver, it will appear here.</span></div>`;
  }

  return `<div class="member-waiver-list">${waivers.map(w => `
    <article class="member-waiver-card">
      <div>
        <span class="pill pill-green">Signed</span>
        <strong>${Pyrk.esc(w.walk_title || 'Walk')}</strong>
        <small>${formatDate(w.walk_date)} ${w.start_time ? '· ' + formatTime(w.start_time) : ''} · ${Pyrk.esc(w.route_name || '')}</small>
        <small>Signed as: ${Pyrk.esc(w.signed_name || '—')}</small>
      </div>
      <div class="member-waiver-meta">
        <strong>${Pyrk.formatDateTime(w.signed_at)}</strong>
        <small>${Pyrk.esc(w.waiver_title || 'Waiver')} v${Number(w.waiver_version || 1)}</small>
        <small>${Pyrk.esc(w.ip_address || 'No IP')}</small>
      </div>
      <div class="inline-controls tiny-controls member-waiver-actions">
        <a class="btn btn-small" href="waivers.php?waiver_id=${Number(w.id)}">View</a>
        <a class="btn btn-light btn-small" href="waivers.php?member_id=${Number(memberId || 0)}">All waivers</a>
      </div>
    </article>`).join('')}</div>`;
}


function renderProfilePhotos(photos) {
  if (!photos || !photos.length) return '<p class="muted">No photos uploaded yet.</p>';
  return `<div class="profile-photo-grid">${photos.map(p => `
    <article class="profile-photo-card">
      <img src="${Pyrk.esc(publicAsset(p.thumbnail_path || p.file_path))}" alt="${Pyrk.esc(p.title || 'Photo')}">
      <div>
        <strong>${Pyrk.esc(p.title || 'Photo')}</strong>
        <small>${Pyrk.esc(p.walk_title || '')} · ${Pyrk.esc(p.route_name || '')}</small>
        <div class="inline-controls tiny-controls">${statusPill(p.status)}<span class="pill pill-muted">${Number(p.votes_count || 0)} votes</span></div>
      </div>
    </article>`).join('')}</div>`;
}

function renderProfileBadges(badges) {
  if (!badges || !badges.length) return '<p class="muted">No badges earned yet.</p>';
  return `<div class="profile-badge-grid">${badges.map(b => `<div class="profile-badge"><span>${Pyrk.esc(b.badge_icon || '🏅')}</span><strong>${Pyrk.esc(b.badge_name)}</strong><small>${formatDate(b.earned_at)}</small></div>`).join('')}</div>`;
}


function renderProfileLogins(logs) {
  if (!logs || !logs.length) return '<p class="muted">No login history recorded yet.</p>';
  return `<div class="table-wrap compact-table-wrap"><table class="pro-table compact-pro-table"><thead><tr><th>Login</th><th>Status</th><th>IP</th><th>Logout</th></tr></thead><tbody>${logs.map(l => `
    <tr>
      <td><strong>${Pyrk.formatDateTime(l.login_at)}</strong><small>${Pyrk.esc((l.user_agent || '').slice(0, 80))}</small></td>
      <td>${Number(l.success || 0) === 1 ? '<span class="pill pill-green">Success</span>' : `<span class="pill pill-red">Failed</span><small>${Pyrk.esc(l.failure_reason || '')}</small>`}</td>
      <td>${Pyrk.esc(l.ip_address || '—')}</td>
      <td>${l.logout_at ? `${Pyrk.formatDateTime(l.logout_at)}<small>${Pyrk.esc(l.logout_reason || '')}</small>` : '<span class="muted">Open / unknown</span>'}</td>
    </tr>`).join('')}</tbody></table></div>`;
}

function renderProfileTransactions(transactions) {
  if (!transactions || !transactions.length) return '<p class="muted">No loyalty transactions yet.</p>';
  return `<div class="table-wrap compact-table-wrap"><table class="pro-table compact-pro-table"><thead><tr><th>Date</th><th>Type</th><th>Description</th><th>Points</th></tr></thead><tbody>${transactions.map(t => `
    <tr>
      <td>${formatDate(t.created_at)}</td>
      <td>${statusPill(t.transaction_type)}</td>
      <td><strong>${Pyrk.esc(t.description || '—')}</strong><small>${Pyrk.esc(t.walk_title || '')}</small></td>
      <td><strong class="${Number(t.points || 0) < 0 ? 'bad' : 'ok'}">${Number(t.points || 0) > 0 ? '+' : ''}${Number(t.points || 0)}</strong></td>
    </tr>`).join('')}</tbody></table></div>`;
}


function renderMemberProfileGroups(groups) {
  if (!groups || !groups.length) {
    return '<p class="muted">This member is not assigned to any group yet.</p>';
  }
  return `<div class="profile-groups-list">${groups.map(group => `
    <span class="profile-group-pill">👥 ${Pyrk.esc(group.group_name || 'Group')}</span>
  `).join('')}</div>`;
}

function renderProfile(member, walks, photos, badges, transactions, loginLogs, memberGroups = [], waivers = []) {
  document.getElementById('profileMemberName').textContent = personDisplayName(member, 'Member profile');
  const genderText = String(member.gender || '').replace(/_/g, ' ');
  const consentText = Number(member.photo_consent || 0) === 1 ? 'Approved' : 'Not approved';
  const lockedUntil = member.locked_until ? Pyrk.formatDateTime(member.locked_until) : 'Not locked';
  const blockedAt = member.blocked_at ? Pyrk.formatDateTime(member.blocked_at) : '—';

  document.getElementById('memberProfileContent').innerHTML = `
    <section class="member-profile-hero member-profile-hero-pro">
      ${avatarHtml(member, 'xl')}
      <div>
        <h3>${Pyrk.esc(member.full_name)}</h3>
        <p class="muted">${Pyrk.esc(member.email)} · ${Pyrk.esc(member.mobile || 'No mobile')}</p>
        <div class="inline-controls profile-pills">${statusPill(member.status)}<span class="pill pill-muted">${member.age ? `${member.age} yrs` : 'Age not set'}</span><span class="pill pill-muted">${Pyrk.esc(genderText || 'Gender not set')}</span></div>
      </div>
      <div class="profile-quick-actions">
        ${window.PYRK_CAN_EDIT_MEMBERS ? `<button class="btn btn-small" type="button" onclick="editMember(${member.id})">Edit member</button>` : ''}${window.PYRK_CAN_DELETE_MEMBERS ? `<button class="btn btn-danger btn-small" type="button" onclick="deleteMember(${member.id}, '${Pyrk.esc(member.full_name || 'member').replace(/'/g, '&#39;')}')">Delete member</button>` : ''}
        <a class="btn btn-light btn-small" href="loyalty.php?member_id=${member.id}">Manage loyalty</a>
      </div>
    </section>

    <section class="grid four profile-stat-grid">
      <div class="stat stat-pro"><span>Walks</span><strong>${Number(member.total_walks || 0)}</strong></div>
      <div class="stat stat-pro"><span>Kilometers</span><strong>${Number(member.total_kilometers || 0).toFixed(1)}</strong></div>
      <div class="stat stat-pro"><span>Points</span><strong>${Number(member.loyalty_points || 0)}</strong></div>
      <div class="stat stat-pro"><span>Photos</span><strong>${Number(member.photos_count || 0)}</strong></div>
    </section>

    <section class="profile-full-info-grid">
      <article class="profile-info-card profile-info-card-pro">
        <h4>Personal & contact</h4>
        ${profileField('Member ID', `#${member.id}`)}
        ${profileField('First Name', personFirstName(member))}
        ${profileField('Last Name', personLastName(member))}
        ${profileField('Email', member.email)}
        ${profileField('Mobile', member.mobile)}
        ${profileField('Date of birth', formatDate(member.date_of_birth))}
        ${profileField('Age', member.age ? `${member.age} years` : '')}
        ${profileField('Gender', genderText)}
      </article>

      <article class="profile-info-card profile-info-card-pro">
        <h4>Groups</h4>
        ${renderMemberProfileGroups(memberGroups)}
      </article>

      <article class="profile-info-card profile-info-card-pro">
        <h4>Emergency & medical</h4>
        ${profileField('Emergency contact', member.emergency_contact_name)}
        ${profileField('Emergency mobile', member.emergency_contact_mobile)}
        ${profileField('Photo consent', consentText)}
        <div class="profile-field-row profile-field-row-block"><span>Medical conditions</span><strong>${member.medical_conditions ? Pyrk.esc(member.medical_conditions) : 'No medical notes recorded.'}</strong></div>
      </article>

      <article class="profile-info-card profile-info-card-pro">
        <h4>Activity summary</h4>
        ${profileField('Registrations', member.registrations_count || '0')}
        ${profileField('Completed walks', member.total_walks || '0')}
        ${profileField('Total kilometers', `${Number(member.total_kilometers || 0).toFixed(2)} KM`)}
        ${profileField('Loyalty points', member.loyalty_points || '0')}
        ${profileField('Badges', member.badges_count || (badges ? badges.length : 0))}
        ${profileField('Uploaded photos', member.photos_count || (photos ? photos.length : 0))}
      </article>

      <article class="profile-info-card profile-info-card-pro">
        <h4>Account & system</h4>
        ${profileFieldHtml('Status', statusPill(member.status))}
        ${profileField('QR token', member.qr_token)}
        ${profileField('Blocked at', blockedAt)}
        ${profileField('Blocked reason', member.blocked_reason)}
        ${profileField('Created', member.created_at ? Pyrk.formatDateTime(member.created_at) : '')}
        ${profileField('Updated', member.updated_at ? Pyrk.formatDateTime(member.updated_at) : '')}
      </article>
    </section>

    <section class="profile-tabs-grid">
      <article class="profile-panel profile-waivers-panel"><div class="section-head"><h3>Signed waivers</h3><a class="btn btn-small btn-light" href="waivers.php?member_id=${member.id}">Open archive</a></div>${renderProfileWaivers(waivers, member.id)}</article>
      <article class="profile-panel"><div class="section-head"><h3>Routes / walks registered</h3></div>${renderProfileWalks(walks)}</article>
      <article class="profile-panel"><div class="section-head"><h3>Photos</h3></div>${renderProfilePhotos(photos)}</article>
      <article class="profile-panel"><div class="section-head"><h3>Badges</h3></div>${renderProfileBadges(badges)}</article>
      <article class="profile-panel"><div class="section-head"><h3>Loyalty transactions</h3><a class="btn btn-small btn-light" href="loyalty.php?member_id=${member.id}">Open loyalty</a></div>${renderProfileTransactions(transactions)}</article>
    </section>`;
}

window.openMemberProfile = async function openMemberProfile(id) {
  openModal('memberProfileModal');
  document.getElementById('profileMemberName').textContent = 'Member profile';
  document.getElementById('memberProfileContent').innerHTML = '<p class="muted">Loading profile...</p>';
  try {
    const res = await Pyrk.get('members.php', {action:'detail', id});
    if (!res.ok) {
      document.getElementById('memberProfileContent').innerHTML = `<div class="notice bad"><strong>Could not load profile.</strong><br>${Pyrk.esc(res.message || 'Unknown API error.')}</div>`;
      return;
    }
    renderProfile(res.data.member, res.data.walks || [], res.data.photos || [], res.data.badges || [], res.data.transactions || [], [], res.data.member_groups || [], res.data.waivers || []);
  } catch (error) {
    document.getElementById('memberProfileContent').innerHTML = `<div class="notice bad"><strong>Could not load profile.</strong><br>${Pyrk.esc(error.message || error)}</div>`;
  }
};



window.deleteMember = async function deleteMember(id, name = 'this member') {
  if (!window.PYRK_CAN_DELETE_MEMBERS) { alert('You do not have permission to delete members.'); return; }
  const confirmed = confirm(`Delete ${name} permanently?\n\nThis removes the member account and related member records. This action cannot be undone.`);
  if (!confirmed) return;
  const res = await Pyrk.post('members.php', {action:'delete_member', id});
  alert(res.message || (res.ok ? 'Deleted' : 'Error'));
  if (res.ok) {
    closeModal('memberProfileModal');
    await loadMembers();
  }
};

window.blockMember = async function blockMember(id) {
  const reason = prompt('Reason for blocking this member:', 'Blocked by admin');
  if (reason === null) return;
  const res = await Pyrk.post('members.php', {action:'block_member', id, reason});
  alert(res.message || (res.ok ? 'Blocked' : 'Error'));
  await loadMembers();
};

window.unblockMember = async function unblockMember(id) {
  if (!confirm('Unblock this member and set status to active?')) return;
  const res = await Pyrk.post('members.php', {action:'unblock_member', id});
  alert(res.message || (res.ok ? 'Unblocked' : 'Error'));
  await loadMembers();
};

window.resetMemberLock = async function resetMemberLock(id) {
  if (!confirm('Reset failed attempts and temporary login lock for this member?')) return;
  const res = await Pyrk.post('members.php', {action:'reset_lock', id});
  alert(res.message || (res.ok ? 'Reset' : 'Error'));
  await loadMembers();
};

async function loadMembers() {
  const res = await Pyrk.get('members.php', {action:'admin_list'});
  if (!res.ok) { document.getElementById('membersTableBody').innerHTML = `<tr><td colspan="9" class="bad">${Pyrk.esc(res.message)}</td></tr>`; return; }
  allMembers = res.data.members || [];
  pruneBulkSelection();
  memberSystemRoles = res.data.roles || memberSystemRoles || [];
  memberPermissionCatalog = res.data.permissions_catalog || memberPermissionCatalog || [];
  renderMemberSystemRoles();
  try {
    const groupsRes = await Pyrk.get('groups.php', {action:'list'});
    if (groupsRes.ok) {
      allMemberGroups = groupsRes.data.groups || [];
      renderMemberGroupsEditor();
    }
  } catch (e) {
    allMemberGroups = allMemberGroups || [];
  }
  computeMemberStats();
  renderMembers();
  const params = new URLSearchParams(window.location.search);
  if ((params.get('create') === '1' || window.location.hash === '#create') && window.PYRK_CAN_EDIT_MEMBERS) { openNewMember(); }
  if (params.get('open')) { openMemberProfile(Number(params.get('open'))); }
}

const form = document.getElementById('memberForm');
document.getElementById('firstName')?.addEventListener('input', () => syncPersonNameHidden('firstName', 'lastName', 'fullName'));
document.getElementById('lastName')?.addEventListener('input', () => syncPersonNameHidden('firstName', 'lastName', 'fullName'));



document.getElementById('memberSystemAccessEnabled')?.addEventListener('change', updateMemberPrivilegeVisibility);
document.getElementById('memberSystemRoleId')?.addEventListener('change', setMemberPrivilegesFromRoleDefaults);
document.getElementById('memberPermissionSearch')?.addEventListener('input', renderMemberPermissions);
document.getElementById('memberPermissionsRoleDefault')?.addEventListener('click', setMemberPrivilegesFromRoleDefaults);
document.getElementById('memberPermissionsSelectAll')?.addEventListener('click', () => {
  selectedMemberPermissions = new Set((memberPermissionCatalog || []).flatMap(group => (group.items || []).map(item => String(item.key || '')).filter(Boolean)));
  renderMemberPermissions();
});
document.getElementById('memberPermissionsClear')?.addEventListener('click', () => {
  selectedMemberPermissions.clear();
  renderMemberPermissions();
});
document.getElementById('memberPermissionsList')?.addEventListener('change', e => {
  const input = e.target.closest('input[type="checkbox"]');
  if (!input) return;
  if (input.checked) selectedMemberPermissions.add(input.value);
  else selectedMemberPermissions.delete(input.value);
  renderMemberPermissions();
});


if (form) {
  form.addEventListener('submit', async e => {
    e.preventDefault();
    syncPhoneHidden();
    syncPersonNameHidden('firstName', 'lastName', 'fullName');
    const fd = new FormData(form);
    try {
      appendMemberPrivilegeData(fd);
    } catch (error) {
      Pyrk.toast('memberMsg', {ok:false, message:error.message || 'Check system privileges.'});
      return;
    }
    if (fd.get('date_of_birth')) fd.set('date_of_birth', Pyrk.isoFromDmy(fd.get('date_of_birth')));
    fd.append('action', document.getElementById('memberId').value ? 'update_member' : 'create_member');
    if (!document.getElementById('photoConsent').checked) fd.set('photo_consent', '0');
    appendSelectedGroupsToFormData(fd);
    const res = await Pyrk.postForm('members.php', fd);
    Pyrk.toast('memberMsg', res);
    if (res.ok) {
      await loadMembers();
      setTimeout(() => closeModal('memberFormModal'), 550);
    }
  });
  document.getElementById('memberProfilePhoto').addEventListener('change', e => {
    const file = e.target.files && e.target.files[0];
    if (!file) return;
    const url = URL.createObjectURL(file);
    document.getElementById('memberAvatarPreview').outerHTML = `<img class="avatar-preview xl" id="memberAvatarPreview" src="${url}" alt="Preview">`;
  });
}

for (const btn of [document.getElementById('openNewMemberModal'), document.getElementById('openNewMemberModalSmall')]) {
  if (btn) btn.addEventListener('click', openNewMember);
}

document.querySelectorAll('[data-close-modal]').forEach(btn => btn.addEventListener('click', () => closeModal(btn.dataset.closeModal)));
document.querySelectorAll('.modal-backdrop').forEach(modal => modal.addEventListener('click', e => { if (e.target === modal) closeModal(modal.id); }));
document.addEventListener('keydown', e => { if (e.key === 'Escape') document.querySelectorAll('.modal-backdrop:not([hidden])').forEach(m => closeModal(m.id)); });

document.getElementById('memberSearch').addEventListener('input', renderMembers);
document.getElementById('memberStatusFilter').addEventListener('change', renderMembers);
document.getElementById('memberViewMode').addEventListener('change', renderMembers);
document.getElementById('memberBulkSelectShown')?.addEventListener('change', e => setShownInactiveSelection(e.target.checked));
document.getElementById('memberBulkSelectInactive')?.addEventListener('click', () => setShownInactiveSelection(true));
document.getElementById('memberBulkActivate')?.addEventListener('click', bulkActivateSelectedMembers);

function initMemberFormEnhancements() {
  maskDmyDateInput(document.getElementById('dateOfBirth'));

  ['mobile', 'emergency'].forEach(widget => {
    renderCountryOptions(widget, '');
    const button = document.querySelector(`[data-country-button="${widget}"]`);
    const search = document.querySelector(`[data-country-search="${widget}"]`);
    const options = document.querySelector(`[data-country-options="${widget}"]`);

    if (button) button.addEventListener('click', e => {
      e.preventDefault();
      openCountryDropdown(widget);
    });

    if (search) search.addEventListener('input', () => renderCountryOptions(widget, search.value));

    if (options) options.addEventListener('click', e => {
      const option = e.target.closest('[data-country-code]');
      if (!option) return;
      selectCountry(widget, option.dataset.countryCode, option.dataset.countryName);
      closeCountryDropdowns();
    });
  });

  document.addEventListener('click', e => {
    if (!e.target.closest('.country-select-pro')) closeCountryDropdowns();
  });

  const dateInput = document.getElementById('dateOfBirth');
  const datePicker = document.getElementById('dateOfBirthPicker');
  const dateBtn = document.getElementById('dateOfBirthCalendarBtn');
  if (dateBtn && datePicker && dateInput) {
    dateBtn.addEventListener('click', () => {
      if (typeof datePicker.showPicker === 'function') datePicker.showPicker();
      else datePicker.focus();
    });
    datePicker.addEventListener('change', () => {
      if (datePicker.value) dateInput.value = Pyrk.dmyFromIso(datePicker.value);
    });
  }

  const passwordBtn = document.getElementById('toggleMemberPassword');
  if (passwordBtn) {
    passwordBtn.addEventListener('click', () => {
      const input = document.getElementById('password');
      setMemberPasswordVisible(input && input.type === 'password');
    });
  }

  ['mobileNumber', 'emergencyMobileNumber'].forEach(id => {
    const el = document.getElementById(id);
    if (el) el.addEventListener('input', syncPhoneHidden);
  });

  setPhoneInputs('', 'mobile', 'mobileNumber');
  setPhoneInputs('', 'emergency', 'emergencyMobileNumber');
  resetMemberSystemPrivilegeForm();
  const emailInput = document.getElementById('email');
  if (emailInput) emailInput.readOnly = false;

  const groupSearch = document.getElementById('memberGroupSearch');
  if (groupSearch) groupSearch.addEventListener('input', renderMemberGroupsEditor);

  const selectAllGroupsBtn = document.getElementById('selectAllMemberGroupsBtn');
  if (selectAllGroupsBtn) selectAllGroupsBtn.addEventListener('click', () => {
    allMemberGroups.forEach(group => selectedMemberGroups.add(Number(group.id)));
    renderMemberGroupsEditor();
  });

  const clearGroupsBtn = document.getElementById('clearMemberGroupsBtn');
  if (clearGroupsBtn) clearGroupsBtn.addEventListener('click', () => {
    selectedMemberGroups.clear();
    renderMemberGroupsEditor();
  });
}

initMemberFormEnhancements();

loadMembers();
