'use strict';

const App = (() => {

  // ── State ──────────────────────────────────────────────────────────────────
  let currentPage = 'dashboard';
  let editingWebhookId = null;
  const PAGE_SIZE = 20;
  let receivedOffset = 0;
  let sentOffset = 0;

  // ── API helper ─────────────────────────────────────────────────────────────
  async function api(method, path, body) {
    const opts = {
      method,
      credentials: 'include',
      headers: { 'Content-Type': 'application/json' },
    };
    if (body !== undefined) opts.body = JSON.stringify(body);
    const res = await fetch('/api' + path, opts);
    const data = await res.json();
    if (!res.ok) throw new Error(data.error || `HTTP ${res.status}`);
    return data;
  }

  // ── Toast ──────────────────────────────────────────────────────────────────
  function toast(msg, type = 'info') {
    const el = document.createElement('div');
    el.className = `toast toast-${type}`;
    const icons = { success: '✅', error: '❌', info: 'ℹ️' };
    el.innerHTML = `<span>${icons[type] || ''}</span><span>${msg}</span>`;
    document.getElementById('toast-container').appendChild(el);
    setTimeout(() => el.remove(), 4000);
  }

  function showAlert(id, msg, type = 'danger') {
    const el = document.getElementById(id);
    if (!el) return;
    el.className = `alert alert-${type}`;
    el.textContent = msg;
    el.style.display = 'flex';
  }
  function hideAlert(id) {
    const el = document.getElementById(id);
    if (el) el.style.display = 'none';
  }

  // ── Formatters ─────────────────────────────────────────────────────────────
  function fmt(dateStr) {
    if (!dateStr) return '—';
    try {
      return new Date(dateStr).toLocaleString();
    } catch { return dateStr; }
  }

  function statusBadge(status) {
    const map = {
      sent:     ['badge-blue',   'Sent'],
      received: ['badge-green',  'Received'],
      failed:   ['badge-red',    'Failed'],
      pending:  ['badge-yellow', 'Pending'],
    };
    const [cls, label] = map[status] || ['badge-gray', status];
    return `<span class="badge ${cls}">${label}</span>`;
  }

  function esc(str) {
    const div = document.createElement('div');
    div.textContent = str;
    return div.innerHTML;
  }

  // ── Navigation ─────────────────────────────────────────────────────────────
  function navigate(page) {
    currentPage = page;
    document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
    document.querySelectorAll('.nav-item').forEach(n => n.classList.remove('active'));
    document.getElementById(`page-${page}`)?.classList.add('active');
    document.querySelector(`.nav-item[data-page="${page}"]`)?.classList.add('active');

    // Load data for page
    const loaders = {
      dashboard: loadDashboard,
      received:  loadReceived,
      sent:      loadSent,
      webhooks:  loadWebhooks,
      tokens:    loadTokens,
      settings:  loadSettings,
    };
    loaders[page]?.();
  }

  // ── Auth ───────────────────────────────────────────────────────────────────
  async function checkAuth() {
    try {
      const me = await api('GET', '/auth/me');
      if (me.authenticated) {
        showApp(me.username);
        loadDashboard();
      } else {
        showLogin();
      }
    } catch {
      showLogin();
    }
  }

  function showLogin() {
    document.getElementById('login-page').classList.add('active');
    document.getElementById('sidebar').style.display = 'none';
    document.getElementById('main').style.display = 'none';
  }

  function showApp(username) {
    document.getElementById('login-page').classList.remove('active');
    document.getElementById('sidebar').style.display = 'flex';
    document.getElementById('main').style.display = 'flex';
    document.getElementById('user-name').textContent = username || 'Admin';
    document.getElementById('user-avatar').textContent = (username || 'A')[0].toUpperCase();
  }

  async function login(e) {
    e.preventDefault();
    const username = document.getElementById('login-username').value.trim();
    const password = document.getElementById('login-password').value;
    hideAlert('login-error');
    try {
      await api('POST', '/auth/login', { username, password });
      showApp(username);
      loadDashboard();
    } catch (err) {
      showAlert('login-error', err.message || 'Login failed');
    }
  }

  async function logout() {
    await api('POST', '/auth/logout');
    showLogin();
  }

  // ── Dashboard ──────────────────────────────────────────────────────────────
  async function loadDashboard() {
    try {
      const [stats, msgs] = await Promise.all([
        api('GET', '/stats'),
        api('GET', '/sms/messages?limit=10'),
      ]);
      document.getElementById('stat-sent').textContent     = stats.sent     ?? 0;
      document.getElementById('stat-received').textContent = stats.received ?? 0;
      document.getElementById('stat-failed').textContent   = stats.failed   ?? 0;

      const tbody = document.getElementById('recent-messages');
      if (!msgs.length) {
        tbody.innerHTML = '<tr><td colspan="5"><div class="empty-state"><div class="icon">📭</div>No messages yet</div></td></tr>';
      } else {
        tbody.innerHTML = msgs.map(m => `
          <tr>
            <td><span class="dir-indicator" title="${m.direction}">${m.direction === 'received' ? '📥' : '📤'}</span></td>
            <td><span class="phone">${esc(m.phone_number)}</span></td>
            <td><span class="msg-text" title="${esc(m.message)}">${esc(m.message)}</span></td>
            <td>${statusBadge(m.status)}</td>
            <td style="color:var(--muted);font-size:12px;">${fmt(m.created_at)}</td>
          </tr>`).join('');
      }
    } catch (err) {
      toast('Failed to load dashboard: ' + err.message, 'error');
    }
  }

  function refreshDashboard() { loadDashboard(); }

  // ── Received ───────────────────────────────────────────────────────────────
  async function loadReceived(offset = 0) {
    receivedOffset = offset;
    const tbody = document.getElementById('received-list');
    tbody.innerHTML = '<tr><td colspan="3"><div class="empty-state"><div class="spinner"></div></div></td></tr>';
    try {
      const msgs = await api('GET', `/sms/messages/received?limit=${PAGE_SIZE}&offset=${offset}`);
      if (!msgs.length) {
        tbody.innerHTML = '<tr><td colspan="3"><div class="empty-state"><div class="icon">📭</div>No received messages</div></td></tr>';
      } else {
        tbody.innerHTML = msgs.map(m => `
          <tr>
            <td><span class="phone">${esc(m.phone_number)}</span></td>
            <td>${esc(m.message)}</td>
            <td style="color:var(--muted);font-size:12px;">${fmt(m.created_at)}</td>
          </tr>`).join('');
      }
      renderPagination('received-pagination', offset, msgs.length, loadReceived);
    } catch (err) {
      toast('Failed to load received messages: ' + err.message, 'error');
    }
  }

  // ── Sent ───────────────────────────────────────────────────────────────────
  async function loadSent(offset = 0) {
    sentOffset = offset;
    const tbody = document.getElementById('sent-list');
    tbody.innerHTML = '<tr><td colspan="4"><div class="empty-state"><div class="spinner"></div></div></td></tr>';
    try {
      const msgs = await api('GET', `/sms/messages/sent?limit=${PAGE_SIZE}&offset=${offset}`);
      if (!msgs.length) {
        tbody.innerHTML = '<tr><td colspan="4"><div class="empty-state"><div class="icon">📤</div>No sent messages</div></td></tr>';
      } else {
        tbody.innerHTML = msgs.map(m => `
          <tr>
            <td><span class="phone">${esc(m.phone_number)}</span></td>
            <td>${esc(m.message)}</td>
            <td>${statusBadge(m.status)}</td>
            <td style="color:var(--muted);font-size:12px;">${fmt(m.created_at)}</td>
          </tr>`).join('');
      }
      renderPagination('sent-pagination', offset, msgs.length, loadSent);
    } catch (err) {
      toast('Failed to load sent messages: ' + err.message, 'error');
    }
  }

  function renderPagination(id, offset, count, loader) {
    const el = document.getElementById(id);
    if (!el) return;
    const hasPrev = offset > 0;
    const hasNext = count === PAGE_SIZE;
    el.innerHTML = `
      ${hasPrev ? `<button class="btn btn-sm btn-outline" onclick="App._paginate('${id}',${offset - PAGE_SIZE})">← Prev</button>` : ''}
      <span style="color:var(--muted);font-size:12px;">Page ${Math.floor(offset / PAGE_SIZE) + 1}</span>
      ${hasNext ? `<button class="btn btn-sm btn-outline" onclick="App._paginate('${id}',${offset + PAGE_SIZE})">Next →</button>` : ''}
    `;
  }

  function _paginate(paginationId, offset) {
    if (paginationId === 'received-pagination') loadReceived(offset);
    else if (paginationId === 'sent-pagination') loadSent(offset);
  }

  // ── Send SMS ───────────────────────────────────────────────────────────────
  async function sendSMS(e) {
    e.preventDefault();
    const number  = document.getElementById('send-number').value.trim();
    const message = document.getElementById('send-message').value.trim();
    hideAlert('send-alert');
    if (!number || !message) {
      showAlert('send-alert', 'Phone number and message are required');
      return;
    }
    const btn = document.getElementById('send-btn');
    btn.disabled = true;
    btn.textContent = 'Sending…';
    try {
      await api('POST', '/sms/send', { number, message });
      toast(`Message sent to ${number}`, 'success');
      document.getElementById('send-number').value  = '';
      document.getElementById('send-message').value = '';
      document.getElementById('char-count').textContent = '0';
    } catch (err) {
      showAlert('send-alert', 'Failed to send: ' + err.message);
    } finally {
      btn.disabled = false;
      btn.textContent = '✉️ Send Message';
    }
  }

  async function triggerPoll() {
    try {
      await api('POST', '/sms/poll');
      toast('Device polled for new messages', 'success');
      if (currentPage === 'received') loadReceived(receivedOffset);
    } catch (err) {
      toast('Poll failed: ' + err.message, 'error');
    }
  }

  // ── Webhooks ───────────────────────────────────────────────────────────────
  async function loadWebhooks() {
    const tbody = document.getElementById('webhook-list');
    try {
      const hooks = await api('GET', '/webhooks');
      if (!hooks.length) {
        tbody.innerHTML = '<tr><td colspan="6"><div class="empty-state"><div class="icon">🔗</div>No webhooks configured</div></td></tr>';
      } else {
        tbody.innerHTML = hooks.map(h => {
          const evtBadge = { received: 'badge-green', sent: 'badge-blue', both: 'badge-yellow' }[h.events] || 'badge-gray';
          return `
            <tr>
              <td><strong>${esc(h.name)}</strong></td>
              <td><span class="phone">${h.phone_number ? esc(h.phone_number) : '<span style="color:var(--muted)">All numbers</span>'}</span></td>
              <td style="font-size:12px;max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;"
                  title="${esc(h.url)}">${esc(h.url)}</td>
              <td><span class="badge ${evtBadge}">${h.events}</span></td>
              <td>
                <label class="toggle">
                  <input type="checkbox" ${h.active ? 'checked' : ''} onchange="App.toggleWebhook(${h.id}, this.checked)" />
                  <span class="toggle-slider"></span>
                </label>
              </td>
              <td style="display:flex;gap:6px;">
                <button class="btn btn-sm btn-outline btn-icon" onclick="App.openWebhookModal(${h.id})" title="Edit">✏️</button>
                <button class="btn btn-sm btn-danger btn-icon" onclick="App.deleteWebhook(${h.id})" title="Delete">🗑</button>
              </td>
            </tr>`;
        }).join('');
      }
    } catch (err) {
      toast('Failed to load webhooks: ' + err.message, 'error');
    }
  }

  function openWebhookModal(id) {
    editingWebhookId = id || null;
    document.getElementById('webhook-modal-title').textContent = id ? 'Edit Webhook' : 'Add Webhook';
    // Reset fields
    ['wh-name','wh-url','wh-phone','wh-headers'].forEach(f => document.getElementById(f).value = '');
    document.getElementById('wh-method').value = 'POST';
    document.getElementById('wh-events').value = 'received';

    if (id) {
      // Populate from existing (fetch from list in DOM for simplicity)
      api('GET', '/webhooks').then(hooks => {
        const h = hooks.find(x => x.id === id);
        if (!h) return;
        document.getElementById('wh-name').value   = h.name  || '';
        document.getElementById('wh-url').value    = h.url   || '';
        document.getElementById('wh-phone').value  = h.phone_number || '';
        document.getElementById('wh-method').value = h.method || 'POST';
        document.getElementById('wh-events').value = h.events || 'received';
        if (h.headers) {
          try { document.getElementById('wh-headers').value = JSON.stringify(JSON.parse(h.headers), null, 2); } catch {}
        }
      });
    }
    openModal('webhook-modal');
  }

  async function saveWebhook() {
    const name         = document.getElementById('wh-name').value.trim();
    const url          = document.getElementById('wh-url').value.trim();
    const phone_number = document.getElementById('wh-phone').value.trim();
    const method       = document.getElementById('wh-method').value;
    const events       = document.getElementById('wh-events').value;
    const rawHeaders   = document.getElementById('wh-headers').value.trim();

    if (!name || !url) { toast('Name and URL are required', 'error'); return; }

    let headers = null;
    if (rawHeaders) {
      try { headers = JSON.parse(rawHeaders); } catch { toast('Invalid JSON in headers', 'error'); return; }
    }

    const payload = { name, url, method, events, headers };
    if (phone_number) payload.phone_number = phone_number;

    try {
      if (editingWebhookId) {
        await api('PUT', `/webhooks/${editingWebhookId}`, payload);
        toast('Webhook updated', 'success');
      } else {
        await api('POST', '/webhooks', payload);
        toast('Webhook created', 'success');
      }
      closeModal('webhook-modal');
      loadWebhooks();
    } catch (err) {
      toast('Save failed: ' + err.message, 'error');
    }
  }

  async function toggleWebhook(id, active) {
    try {
      await api('PUT', `/webhooks/${id}`, { active: active ? 1 : 0 });
    } catch (err) {
      toast('Update failed: ' + err.message, 'error');
    }
  }

  async function deleteWebhook(id) {
    if (!confirm('Delete this webhook?')) return;
    try {
      await api('DELETE', `/webhooks/${id}`);
      toast('Webhook deleted', 'success');
      loadWebhooks();
    } catch (err) {
      toast('Delete failed: ' + err.message, 'error');
    }
  }

  // ── API Tokens ─────────────────────────────────────────────────────────────
  async function loadTokens() {
    const tbody = document.getElementById('token-list');
    try {
      const tokens = await api('GET', '/tokens');
      if (!tokens.length) {
        tbody.innerHTML = '<tr><td colspan="5"><div class="empty-state"><div class="icon">🔑</div>No API tokens created</div></td></tr>';
      } else {
        tbody.innerHTML = tokens.map(t => `
          <tr>
            <td><strong>${esc(t.name)}</strong></td>
            <td style="color:var(--muted);font-size:12px;font-family:monospace;">••••••••••••••••</td>
            <td>
              <label class="toggle">
                <input type="checkbox" ${t.active ? 'checked' : ''} onchange="App.toggleApiToken(${t.id}, this.checked)" />
                <span class="toggle-slider"></span>
              </label>
            </td>
            <td style="color:var(--muted);font-size:12px;">${fmt(t.created_at)}</td>
            <td>
              <button class="btn btn-sm btn-danger btn-icon" onclick="App.deleteToken(${t.id})" title="Delete">🗑</button>
            </td>
          </tr>`).join('');
      }
    } catch (err) {
      toast('Failed to load tokens: ' + err.message, 'error');
    }
  }

  function openTokenModal() {
    document.getElementById('token-form').style.display = 'block';
    document.getElementById('token-created').style.display = 'none';
    document.getElementById('token-create-btn').style.display = 'inline-flex';
    document.getElementById('tk-name').value = '';
    openModal('token-modal');
  }

  async function createToken() {
    const name = document.getElementById('tk-name').value.trim();
    if (!name) { toast('Token name is required', 'error'); return; }
    try {
      const tok = await api('POST', '/tokens', { name });
      document.getElementById('new-token-value').textContent = tok.token;
      document.getElementById('token-form').style.display = 'none';
      document.getElementById('token-created').style.display = 'block';
      document.getElementById('token-create-btn').style.display = 'none';
      loadTokens();
    } catch (err) {
      toast('Failed to create token: ' + err.message, 'error');
    }
  }

  function copyToken() {
    const val = document.getElementById('new-token-value').textContent;
    navigator.clipboard?.writeText(val).then(() => toast('Copied to clipboard', 'success'));
  }

  async function toggleApiToken(id, active) {
    try {
      await api('PATCH', `/tokens/${id}`, { active });
    } catch (err) {
      toast('Update failed: ' + err.message, 'error');
    }
  }

  async function deleteToken(id) {
    if (!confirm('Delete this token? Any apps using it will lose access.')) return;
    try {
      await api('DELETE', `/tokens/${id}`);
      toast('Token deleted', 'success');
      loadTokens();
    } catch (err) {
      toast('Delete failed: ' + err.message, 'error');
    }
  }

  // ── Settings ───────────────────────────────────────────────────────────────
  async function loadSettings() {
    try {
      const [cfg, logRes] = await Promise.all([
        api('GET', '/config'),
        api('GET', '/log-level'),
      ]);
      document.getElementById('cfg-ip').value        = cfg.device_ip       || '';
      document.getElementById('cfg-username').value  = cfg.device_username || '';
      document.getElementById('cfg-password').value  = cfg.device_password || '';
      document.getElementById('cfg-modem').value     = cfg.device_modem    || '';
      document.getElementById('cfg-poll').value      = cfg.poll_interval   || '30';
      document.getElementById('cfg-log-level').value = logRes.level        || 'INFO';
    } catch (err) {
      toast('Failed to load settings: ' + err.message, 'error');
    }
  }

  async function saveLogLevel() {
    hideAlert('log-alert');
    const level = document.getElementById('cfg-log-level').value;
    try {
      const result = await api('PUT', '/log-level', { level });
      showAlert('log-alert', `Log level set to ${result.level}`, 'success');
    } catch (err) {
      showAlert('log-alert', 'Failed: ' + err.message);
    }
  }

  async function saveConfig() {
    hideAlert('settings-alert');
    const body = {
      device_ip:       document.getElementById('cfg-ip').value.trim(),
      device_username: document.getElementById('cfg-username').value.trim(),
      device_password: document.getElementById('cfg-password').value,
      device_modem:    document.getElementById('cfg-modem').value.trim(),
      poll_interval:   document.getElementById('cfg-poll').value,
    };
    try {
      await api('PUT', '/config', body);
      showAlert('settings-alert', 'Settings saved successfully', 'success');
      toast('Settings saved', 'success');
    } catch (err) {
      showAlert('settings-alert', 'Save failed: ' + err.message);
    }
  }

  async function testConnection() {
    hideAlert('settings-alert');
    showAlert('settings-alert', 'Testing connection…', 'info');
    try {
      const result = await api('POST', '/config/test');
      if (result.success) {
        showAlert('settings-alert', '✅ Connection successful!', 'success');
      } else {
        showAlert('settings-alert', '❌ Connection failed: ' + result.error);
      }
    } catch (err) {
      showAlert('settings-alert', 'Test failed: ' + err.message);
    }
  }

  async function changePassword() {
    hideAlert('pw-alert');
    const currentPassword = document.getElementById('pw-current').value;
    const newPassword     = document.getElementById('pw-new').value;
    const confirm         = document.getElementById('pw-confirm').value;
    if (newPassword !== confirm) {
      showAlert('pw-alert', 'Passwords do not match');
      return;
    }
    if (newPassword.length < 6) {
      showAlert('pw-alert', 'Password must be at least 6 characters');
      return;
    }
    try {
      await api('PUT', '/auth/password', { currentPassword, newPassword });
      showAlert('pw-alert', 'Password updated successfully', 'success');
      document.getElementById('pw-current').value = '';
      document.getElementById('pw-new').value     = '';
      document.getElementById('pw-confirm').value = '';
    } catch (err) {
      showAlert('pw-alert', err.message);
    }
  }

  // ── Modal helpers ──────────────────────────────────────────────────────────
  function openModal(id)  { document.getElementById(id).classList.add('open'); }
  function closeModal(id) { document.getElementById(id).classList.remove('open'); }

  // ── Init ───────────────────────────────────────────────────────────────────
  function init() {
    // Nav clicks
    document.querySelectorAll('.nav-item').forEach(el => {
      el.addEventListener('click', () => navigate(el.dataset.page));
    });

    // Login form
    document.getElementById('login-form').addEventListener('submit', login);

    // Logout
    document.getElementById('logout-btn').addEventListener('click', logout);

    // Send form
    document.getElementById('send-form').addEventListener('submit', sendSMS);
    document.getElementById('send-message').addEventListener('input', e => {
      document.getElementById('char-count').textContent = e.target.value.length;
    });

    // Close modal on backdrop click
    document.querySelectorAll('.modal-backdrop').forEach(m => {
      m.addEventListener('click', e => { if (e.target === m) m.classList.remove('open'); });
    });

    checkAuth();
  }

  // ── Public API ─────────────────────────────────────────────────────────────
  return {
    init,
    refreshDashboard, loadDashboard,
    triggerPoll,
    openWebhookModal, saveWebhook, toggleWebhook, deleteWebhook,
    openTokenModal, createToken, copyToken, toggleApiToken, deleteToken,
    saveConfig, testConnection, saveLogLevel, changePassword,
    openModal, closeModal,
    _paginate,
  };

})();

document.addEventListener('DOMContentLoaded', App.init);
