// Admin Dashboard & Meters - AJAX + UI controller

// Keep session alive (ping backend every 5 minutes)
setInterval(() => {
  fetch('/core/db_functions.php?action=ping').catch(() => {});
}, 300000);

const AdminUI = (() => {
  const qs  = (s, r = document) => r.querySelector(s);
  const qsa = (s, r = document) => Array.from(r.querySelectorAll(s));
  const PLACEHOLDER = '--';

  const escapeHtml = (v) => {
    if (v === null || v === undefined) return '';
    return String(v)
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&#39;');
  };

  async function fetchJSON(url, opts = {}) {
    const res = await fetch(url, opts);
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    return res.json();
  }

  function applyStatusFilter() {
    const filter = qs('#filterStatus')?.value || 'ALL';
    const rows = qsa('#metersBody tr');

    rows.forEach((row) => {
      const status = row.dataset.status || 'GRAY';
      row.style.display =
        filter === 'ALL' || filter === status ? '' : 'none';
    });
  }

  function computeStatusIcon(lastSyncedAt, isActive) {
    const dot = (color, title) =>
      `<span class="status-dot" title="${escapeHtml(title)}" style="background:${color};"></span>`;

    if (String(isActive) === '0') {
      return dot('#ff4d4f', 'Inactive (disabled)');
    }

    if (
      !lastSyncedAt ||
      lastSyncedAt === 'null' ||
      lastSyncedAt === '0000-00-00 00:00:00'
    ) {
      return dot('#999', 'Never synced');
    }

    const t = new Date(String(lastSyncedAt).replace(' ', 'T'));
    if (Number.isNaN(t.getTime())) {
      return dot('#999', 'Invalid timestamp');
    }

    const now = new Date();
    const diffHours = (now - t) / 36e5;

    if (diffHours <= 2) {
      return dot('#48e072', `Active - updated ${diffHours.toFixed(1)}h ago`);
    }
    if (diffHours <= 24) {
      return dot(
        '#ffcc00',
        `Late - last update ${diffHours.toFixed(1)}h ago`,
      );
    }
    return dot(
      '#ff4d4f',
      `Offline - last update ${diffHours.toFixed(1)}h ago`,
    );
  }

  async function loadStats() {
    const totals = {
      total_meters: PLACEHOLDER,
      active_tenants: PLACEHOLDER,
      total_landlords: PLACEHOLDER,
    };
    try {
      const data = await fetchJSON('/core/db_functions.php?action=stats');
      Object.assign(totals, data || {});
    } catch {
      // leave placeholders
    }
    const setText = (id, v) => {
      const el = qs(`#${id}`);
      if (el) el.textContent = v ?? PLACEHOLDER;
    };
    setText('totalMeters', totals.total_meters);
    setText('activeTenants', totals.active_tenants);
    setText('totalLandlords', totals.total_landlords);
  }

  async function populateLandlords() {
    const sel = qs('#filterLandlord');
    if (!sel) return;
    try {
      const { rows } = await fetchJSON(
        '/core/db_functions.php?action=landlords',
      );
      sel.innerHTML =
        '<option value="">All Landlords</option>' +
        (rows || [])
          .map(
            (r) =>
              `<option value="${escapeHtml(r.id)}">${escapeHtml(
                r.name || `#${r.id}`,
              )}</option>`,
          )
          .join('');
    } catch {
      // ignore, keep existing options
    }
  }

  let currentPage = 1;
  let perPage = 10;
  let totalRows = 0;

  async function loadMeters(page = 1) {
    const tbody = qs('#metersBody');
    const container = qs('#metersTable');
    if (!tbody || !container) return;

    container.classList.add('loading');
    tbody.innerHTML =
      '<tr><td colspan="7" class="muted">Loading...</td></tr>';

    const landlord = qs('#filterLandlord')?.value || '';
    const source = qs('#filterSource')?.value || 'ALL';
    const status = qs('#filterStatus')?.value || 'ALL';
    const search = (qs('#searchMeters')?.value || '').trim();

    const params = new URLSearchParams({
      action: 'meters',
      limit: String(perPage),
      page: String(page),
    });
    if (search) params.set('search', search);
    if (landlord) params.set('landlord_id', landlord);
    if (source !== 'ALL') params.set('source', source);
    if (status !== 'ALL') params.set('status', status);

    let data = { rows: [] };
    try {
      data = await fetchJSON(`/core/db_functions.php?${params.toString()}`);
    } catch (e) {
      console.warn('loadMeters failed', e);
    }

    const rows = data.rows || [];
    totalRows = data.total || rows.length;
    currentPage = page;

    if (!rows.length) {
      tbody.innerHTML =
        '<tr><td colspan="7" class="muted">No meters found</td></tr>';
      container.classList.remove('loading');
      return;
    }

    tbody.innerHTML = rows
      .map((r) => {
        const statusIcon = computeStatusIcon(r.last_synced_at, r.is_active);
        let statusCode = 'GRAY';
        if (statusIcon.includes('#48e072')) statusCode = 'GREEN';
        else if (statusIcon.includes('#ffcc00')) statusCode = 'YELLOW';
        else if (statusIcon.includes('#ff4d4f')) statusCode = 'RED';

        return `
      <tr data-status="${statusCode}">
        <td>${escapeHtml(r.source || '')}</td>
        <td>${escapeHtml(r.serial_number || '')}</td>
        <td>${escapeHtml(r.property_number || '')}</td>
        <td>${escapeHtml(r.landlord_name || '')}</td>
        <td>${escapeHtml(r.tenant_name || '')}</td>
        <td>${escapeHtml(r.last_synced_at || PLACEHOLDER)}</td>
        <td class="status-cell">${statusIcon}</td>
      </tr>`;
      })
      .join('');

    applyStatusFilter();

    const pageInfo = qs('#pageInfo');
    if (pageInfo) pageInfo.textContent = `Page ${currentPage}`;
    container.classList.remove('loading');
  }

  async function fetchHealth() {
    const bar = qs('#healthBar');
    if (!bar) return;
    try {
      const d = await fetchJSON('/core/db_functions.php?action=health');
      const set = (id, status) => {
        const el = qs(`#${id}`);
        if (!el) return;
        el.dataset.status = status || 'unknown';
        el.title = status || 'unknown';
      };
      set('hDb', d.db);
      set('hFlecto', d.flecto_api);
      set('hIammeter', d.iammeter_api);
      set('hCron', d.cron_status);
      set('hToken', d.token_valid);
    } catch {
      // ignore
    }
  }

  async function fetchInsights() {
    const d = await fetchJSON('/core/db_functions.php?action=insights').catch(
      () => ({}),
    );
    const set = (id, v) => {
      const el = qs(`#${id}`);
      if (!el) return;
      const next =
        v === null || v === undefined || v === '' ? PLACEHOLDER : v;
      if (el.textContent !== String(next)) {
        el.textContent = next;
        pulseUpdate(id);
      }
    };
    set(
      'kwhToday',
      d.kwh_today?.toFixed ? d.kwh_today.toFixed(2) : d.kwh_today,
    );
    set(
      'klToday',
      d.kl_today?.toFixed ? d.kl_today.toFixed(2) : d.kl_today,
    );
    set(
      'revenueToday',
      typeof d.revenue_today === 'number'
        ? `R ${d.revenue_today.toFixed(2)}`
        : d.revenue_today,
    );
    set('offlineMeters', d.offline_meters);
    set('activeAlerts', d.active_alerts);
  }

  let chartEW;
  let chartW;

  async function fetchCharts(from, to) {
    if (typeof Chart === 'undefined') return;
    let qsuf = '';
    if (from && to) {
      qsuf = `&from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}`;
    }

    try {
      const ew = await fetchJSON(
        `/core/db_functions.php?action=chart_energy_water${qsuf}`,
      );
      const ctx1 = qs('#chartEnergyWater');
      if (ctx1) {
        if (chartEW) chartEW.destroy();
        chartEW = new Chart(ctx1, {
          type: 'line',
          data: {
            labels: ew.labels || [],
            datasets: (ew.datasets || []).map((ds, i) => ({
              label: ds.label,
              data: ds.data,
              borderColor: i === 0 ? '#7ed957' : '#00ccff',
              backgroundColor:
                i === 0
                  ? 'rgba(126,217,87,0.2)'
                  : 'rgba(0,204,255,0.2)',
              fill: true,
              tension: 0.35,
            })),
          },
          options: {
            responsive: true,
            plugins: {
              legend: { labels: { color: '#e6f5ff' } },
            },
            scales: {
              x: { ticks: { color: '#9bb5c7' } },
              y: { ticks: { color: '#9bb5c7' } },
            },
          },
        });
      }
    } catch {
      // ignore
    }

    try {
      const w = await fetchJSON(
        `/core/db_functions.php?action=chart_wallet${qsuf}`,
      );
      const ctx2 = qs('#chartWallet');
      if (ctx2) {
        if (chartW) chartW.destroy();
        chartW = new Chart(ctx2, {
          type: 'bar',
          data: {
            labels: w.labels || [],
            datasets: (w.datasets || []).map((ds, i) => ({
              label: ds.label,
              data: ds.data,
              backgroundColor:
                i === 0
                  ? 'rgba(0,204,255,0.3)'
                  : 'rgba(255,91,91,0.3)',
              borderColor: i === 0 ? '#00ccff' : '#ff5b5b',
              borderWidth: 1,
            })),
          },
          options: {
            responsive: true,
            plugins: {
              legend: { labels: { color: '#e6f5ff' } },
            },
            scales: {
              x: { ticks: { color: '#9bb5c7' } },
              y: { ticks: { color: '#9bb5c7' } },
            },
          },
        });
      }
    } catch {
      // ignore
    }
  }

  async function fetchFinance() {
    const box = qs('#financeBox');
    if (!box) return;
    try {
      const d = await fetchJSON('/core/db_functions.php?action=finance');
      const set = (id, v) => {
        const el = qs(`#${id}`);
        if (el) el.textContent = v;
      };
      set('finDeposits', `R ${(d.deposits_total ?? 0).toFixed(2)}`);
      set('finPayouts', `R ${(d.payouts_total ?? 0).toFixed(2)}`);
      set('finNet', `R ${(d.net ?? 0).toFixed(2)}`);
      const list = qs('#topLandlords');
      if (list) {
        list.innerHTML = (d.top_landlords || [])
          .map(
            (l) =>
              `<li>${escapeHtml(
                l.landlord_name || `#${l.landlord_id}`,
              )} - R ${Number(l.total || 0).toFixed(2)}</li>`,
          )
          .join('');
      }
    } catch {
      // ignore
    }
  }

  async function fetchAlerts() {
    const body = qs('#alertsBody');
    const count = qs('#alertsCount');
    if (!body) return;

    try {
      const rows = await fetchJSON(
        '/core/db_functions.php?action=alerts',
      );
      const arr = Array.isArray(rows) ? rows : rows.rows || [];

      if (count) count.textContent = `${arr.length} active alert(s)`;

      if (!arr.length) {
        body.innerHTML =
          '<tr><td colspan="5" class="muted">No alerts</td></tr>';
        return;
      }

      body.innerHTML = arr
        .map((a) => {
          let icon = '[SYS]';
          if (a.type === 'IAMMETER') icon = '[IAM]';
          else if (a.type === 'FLECTO') icon = '[FLE]';
          else if (a.type === 'WATER') icon = '[WTR]';

          let badgeClass = 'alert-red';
          if (a.message?.includes('recorded usage')) badgeClass = 'alert-yellow';
          if (a.message?.includes('not reported')) badgeClass = 'alert-red';

          return `
        <tr class="alert-row" data-message="${escapeHtml(a.message)}">
          <td><span class="alert-type-icon">${icon}</span> ${escapeHtml(
            a.type,
          )}</td>
          <td>${escapeHtml(a.meter)}</td>
          <td>${escapeHtml(a.property)}</td>
          <td>${escapeHtml(a.time)}</td>
          <td><span class="alert-badge ${badgeClass}">${escapeHtml(
            a.status,
          )}</span></td>
        </tr>`;
        })
        .join('');

      qsa('.alert-row', body).forEach((row) => {
        row.addEventListener('click', () => {
          row.classList.toggle('expanded');

          const existing = row.nextElementSibling;
          if (existing && existing.classList.contains('alert-message-row')) {
            existing.remove();
            return;
          }

          const msg = row.dataset.message || '';
          row.insertAdjacentHTML(
            'afterend',
            `
          <tr class="alert-message-row">
            <td colspan="5" class="alert-message">${msg}</td>
          </tr>`,
          );
        });
      });
    } catch (err) {
      console.error('fetchAlerts failed', err);
      body.innerHTML =
        '<tr><td colspan="5" class="muted">Error loading alerts</td></tr>';
    }
  }

  async function fetchActivity() {
    const list = qs('#activityFeed');
    if (!list) return;
    try {
      const rows = await fetchJSON(
        '/core/db_functions.php?action=activity',
      );
      const arr = Array.isArray(rows) ? rows : rows.rows || [];
      if (!arr.length) {
        list.innerHTML = '<li class="muted">No recent activity</li>';
        return;
      }
      list.innerHTML = arr
        .map(
          (r) =>
            `<li><span class="time">${escapeHtml(
              r.time || '',
            )}</span> ${escapeHtml(r.event || '')}</li>`,
        )
        .join('');
    } catch {
      list.innerHTML = '<li class="muted">No recent activity</li>';
    }
  }

  function initTools() {
    const btn = qs('#toolsBtn');
    const drawer = qs('#toolsDrawer');
    if (!btn || !drawer) return;

    btn.addEventListener('click', () => {
      drawer.classList.toggle('open');
    });

    qsa('[data-action="manualSync"]').forEach((el) =>
      el.addEventListener('click', async () => {
        await fetch('/core/db_functions.php?action=manual_sync');
        alert('Manual sync triggered successfully');
      }),
    );
    qsa('[data-action="clearCache"]').forEach((el) =>
      el.addEventListener('click', async () => {
        await fetch('/core/db_functions.php?action=clear_cache');
        alert('System cache cleared');
      }),
    );
    qsa('[data-action="viewTokens"]').forEach((el) =>
      el.addEventListener('click', async () => {
        const d = await fetchJSON(
          '/core/db_functions.php?action=get_tokens',
        );
        alert(JSON.stringify(d.tokens || [], null, 2));
      }),
    );
    qsa('[data-action="viewCron"]').forEach((el) =>
      el.addEventListener('click', async () => {
        const d = await fetchJSON(
          '/core/db_functions.php?action=get_cron_logs',
        );
        alert(JSON.stringify(d.logs || [], null, 2));
      }),
    );
    qsa('[data-action="refreshHealth"]').forEach((el) =>
      el.addEventListener('click', fetchHealth),
    );
  }

  function bindLandlordLinks() {
    document.addEventListener('click', async (e) => {
      const a = e.target.closest('.landlord-link');
      if (!a) return;
      e.preventDefault();
      const id = a.dataset.id;
      if (!id) return;
      const d = await fetchJSON(
        `/core/db_functions.php?action=landlord_details&id=${encodeURIComponent(
          id,
        )}`,
      );
      const modal = qs('#landlordModal');
      if (!modal) return;
      modal.querySelector('.landlordName').textContent =
        d.landlord || `Landlord #${id}`;
      modal.querySelector('.meterList').innerHTML = (d.meters || [])
        .map((m) => `<li>${escapeHtml(m.source)}: ${escapeHtml(m.count)}</li>`)
        .join('');
      modal.querySelector('.walletBalance').textContent = `R ${Number(
        d.wallet || 0,
      ).toFixed(2)}`;
      const tx = d.transactions || [];
      const txEl = modal.querySelector('.txList');
      if (txEl) {
        txEl.innerHTML = tx
          .map(
            (t) =>
              `<li><span class="time">${escapeHtml(
                t.time || '',
              )}</span> ${escapeHtml(t.description || '')} - R ${Number(
                t.amount || 0,
              ).toFixed(2)}</li>`,
          )
          .join('');
      }
      modal.classList.add('open');
    });

    document.addEventListener('click', (e) => {
      if (e.target.matches('#landlordModal, #landlordModal .close')) {
        qs('#landlordModal')?.classList.remove('open');
      }
    });
  }

  function bindFilters() {
    qsa('#filterLandlord, #filterSource, #filterStatus').forEach((el) => {
      el.addEventListener('change', () => loadMeters(1));
    });
  }

  function init() {
    // KPIs
    if (qs('#kpiCards')) {
      loadStats();
      setInterval(loadStats, 60000);
    }

    // Health + insights
    if (qs('#healthBar')) {
      fetchHealth();
      setInterval(fetchHealth, 60000);
    }
    if (qs('#insightsCards')) {
      fetchInsights();
      setInterval(fetchInsights, 60000);
    }

    // Charts
    if (qs('#chartEnergyWater') || qs('#chartWallet')) {
      fetchCharts();
      setInterval(fetchCharts, 60000);
      qs('#rangeApply')?.addEventListener('click', () => {
        const from = qs('#dateFrom')?.value;
        const to = qs('#dateTo')?.value;
        fetchCharts(from, to);
      });
    }

    // Finance
    if (qs('#financeBox')) {
      fetchFinance();
      setInterval(fetchFinance, 60000);
    }

    // Alerts + activity
    if (qs('#alertsTable')) {
      fetchAlerts();
      setInterval(fetchAlerts, 15000);
    }
    if (qs('#activityFeed')) {
      fetchActivity();
      setInterval(fetchActivity, 60000);
    }

    initTools();
    bindLandlordLinks();

    // Meters table
    if (qs('#metersTable')) {
      populateLandlords().finally(() => {
        bindFilters();
        loadMeters();
        setInterval(() => loadMeters(currentPage), 60000);
      });

      qs('#searchMeters')?.addEventListener('input', () => loadMeters(1));
      qs('#nextPage')?.addEventListener('click', () =>
        loadMeters(currentPage + 1),
      );
      qs('#prevPage')?.addEventListener('click', () => {
        if (currentPage > 1) loadMeters(currentPage - 1);
      });
      qs('#resetMeterFilters')?.addEventListener('click', () => {
        const landlordSel = qs('#filterLandlord');
        const sourceSel = qs('#filterSource');
        const statusSel = qs('#filterStatus');
        const searchInput = qs('#searchMeters');

        if (landlordSel) landlordSel.value = '';
        if (sourceSel) sourceSel.value = 'ALL';
        if (statusSel) statusSel.value = 'ALL';
        if (searchInput) searchInput.value = '';

        loadMeters(1);
      });
    }

    // Theme toggle
    qs('#themeToggle')?.addEventListener('click', () => {
      document.body.classList.toggle('light');
      localStorage.setItem(
        'themeLight',
        document.body.classList.contains('light') ? '1' : '0',
      );
    });
    if (localStorage.getItem('themeLight') === '1') {
      document.body.classList.add('light');
    }
  }

  return { init };
})();

document.addEventListener('DOMContentLoaded', () => AdminUI.init());

function pulseUpdate(id) {
  const el = document.getElementById(id);
  if (!el) return;
  el.classList.add('pulse');
  setTimeout(() => el.classList.remove('pulse'), 600);
}

