Home

(function () {
  const els = {};
  const state = {
    role: 'user',
    token: null,
    user: null,
    sinceId: 0,
    polling: null,
    targetUserId: 0, // admin selected user
    live: 0,
  };

  function q(id) { return document.getElementById(id); }

  function initEls() {
    els.app = q('ptwcApp');
    els.logo = q('ptwcLogo');
    els.livePill = q('ptwcLivePill');
    els.statusLine = q('ptwcStatusLine');
    els.logoutBtn = q('ptwcLogoutBtn');

    els.loginPanel = q('ptwcLoginPanel');
    els.chatPanel = q('ptwcChatPanel');

    els.tabs = els.app.querySelectorAll('.ptwc-tab');
    els.username = q('ptwcUsername');
    els.password = q('ptwcPassword');
    els.loginBtn = q('ptwcLoginBtn');
    els.loginError = q('ptwcLoginError');

    els.adminBar = q('ptwcAdminBar');
    els.userSelect = q('ptwcUserSelect');
    els.kickBtn = q('ptwcKickBtn');
    els.unkickBtn = q('ptwcUnkickBtn');
    els.liveToggle = q('ptwcLiveToggle');

    els.messages = q('ptwcMessages');
    els.input = q('ptwcInput');
    els.sendBtn = q('ptwcSendBtn');

    els.transcriptEmail = q('ptwcTranscriptEmail');
    els.sendTranscriptBtn = q('ptwcSendTranscriptBtn');
    els.transcriptStatus = q('ptwcTranscriptStatus');
  }

  function api(path, opts = {}) {
    const headers = Object.assign({
      'Content-Type': 'application/json',
      'X-WP-Nonce': PTWC.nonce,
    }, opts.headers || {});

    if (state.token) headers['X-PTWC-Token'] = state.token;

    return fetch(PTWC.restUrl + path, Object.assign({}, opts, { headers }))
      .then(async (r) => {
        const data = await r.json().catch(() => ({}));
        if (!r.ok) throw data;
        return data;
      });
  }

  function setStatus(text) {
    els.statusLine.textContent = text;
  }

  function showError(msg) {
    els.loginError.style.display = 'block';
    els.loginError.textContent = msg || 'Login failed.';
  }

  function clearError() {
    els.loginError.style.display = 'none';
    els.loginError.textContent = '';
  }

  function setRole(role) {
    state.role = role;
    els.tabs.forEach(t => t.classList.toggle('active', t.dataset.role === role));
  }

  function saveSession() {
    localStorage.setItem('ptwc_session', JSON.stringify({
      token: state.token,
      user: state.user,
      role: state.role,
      targetUserId: state.targetUserId,
      sinceId: state.sinceId
    }));
  }

  function loadSession() {
    try {
      const raw = localStorage.getItem('ptwc_session');
      if (!raw) return false;
      const obj = JSON.parse(raw);
      if (!obj || !obj.token) return false;
      state.token = obj.token;
      state.user = obj.user || null;
      state.role = obj.role || 'user';
      state.targetUserId = obj.targetUserId || 0;
      state.sinceId = obj.sinceId || 0;
      return true;
    } catch { return false; }
  }

  function clearSession() {
    localStorage.removeItem('ptwc_session');
    state.token = null;
    state.user = null;
    state.sinceId = 0;
    state.targetUserId = 0;
  }

  function renderLogoVisibility() {
    const show = (state.role === 'admin' && state.live === 1);
    els.logo.style.display = show ? 'flex' : 'none';
  }

  function fmtLocalTime(gmtString) {
    // gmtString like "2025-12-25 20:15:00" (GMT)
    // Convert to ISO-ish: "2025-12-25T20:15:00Z"
    const iso = gmtString.replace(' ', 'T') + 'Z';
    const d = new Date(iso);
    if (isNaN(d.getTime())) return gmtString + ' GMT';
    return d.toLocaleString();
  }

  function addMessage(m) {
    const div = document.createElement('div');
    div.className = 'ptwc-msg ' + (m.sender_role === 'admin' ? 'admin' : 'user');

    const meta = document.createElement('div');
    meta.className = 'ptwc-meta';

    const sender = document.createElement('div');
    sender.className = 'ptwc-sender';
    sender.textContent = m.sender_role === 'admin' ? `Admin (${m.sender_name})` : m.sender_name;

    const time = document.createElement('div');
    time.className = 'ptwc-time';
    time.textContent = fmtLocalTime(m.created_at);

    meta.appendChild(sender);
    meta.appendChild(time);

    const content = document.createElement('div');
    content.className = 'ptwc-content';
    content.innerHTML = m.content_html; // already escaped server-side + linkified

    div.appendChild(meta);
    div.appendChild(content);

    els.messages.appendChild(div);
  }

  function scrollToBottom(smooth = true) {
    const el = els.messages;
    if (!el) return;
    el.scrollTo({
      top: el.scrollHeight,
      behavior: smooth ? 'smooth' : 'auto'
    });
  }

  function enterChatUI() {
    els.loginPanel.style.display = 'none';
    els.chatPanel.style.display = 'flex';
    els.logoutBtn.style.display = 'inline-block';

    setRole(state.role);
    setStatus(state.role === 'admin' ? 'Admin connected.' : 'Connected.');
    clearError();

    els.adminBar.style.display = (state.role === 'admin') ? 'block' : 'none';
  }

  function exitChatUI() {
    els.loginPanel.style.display = 'flex';
    els.chatPanel.style.display = 'none';
    els.logoutBtn.style.display = 'none';
    els.messages.innerHTML = '';
    els.transcriptStatus.textContent = '';
    setStatus('Please log in.');
    clearError();
    renderLogoVisibility();
  }

  async function login() {
    clearError();
    const username = (els.username.value || '').trim();
    const password = (els.password.value || '').trim();

    if (!username || !password) {
      showError('Enter username and password.');
      return;
    }

    const res = await api('/login', {
      method: 'POST',
      body: JSON.stringify({ username, password, role: state.role })
    });

    if (!res.ok) {
      showError(res.error || 'Login failed.');
      return;
    }

    state.token = res.token;
    state.user = res.user;
    state.live = res.live || 0;
    state.sinceId = 0;

    // admin must choose a target user to view
    if (state.role === 'admin') {
      setStatus('Admin connected. Select a user conversation.');
    }

    saveSession();
    enterChatUI();
    renderLogoVisibility();

    await pollOnce(true);
    startPolling();
  }

  async function sendMessage() {
    const text = (els.input.value || '').trim();
    if (!text) return;

    els.input.value = '';
    const payload = { content: text };

    if (state.role === 'admin') {
      if (!state.targetUserId) {
        setStatus('Select a user conversation first.');
        return;
      }
      payload.target_user_id = state.targetUserId;
    }

    try {
      await api('/send', {
        method: 'POST',
        body: JSON.stringify(payload)
      });
      await pollOnce(true);
    } catch (e) {
      if (e && e.kicked) {
        handleKicked();
      } else {
        setStatus('Send failed. Please try again.');
      }
    }
  }

  function handleKicked() {
    stopPolling();
    setStatus('You were dismissed from the chat.');
    clearSession();
    exitChatUI();
    showError('You were dismissed from the chat.');
  }

  function setUsersDropdown(users) {
    if (state.role !== 'admin') return;

    const current = state.targetUserId;
    els.userSelect.innerHTML = '';

    const placeholder = document.createElement('option');
    placeholder.value = '0';
    placeholder.textContent = '— Select a user —';
    els.userSelect.appendChild(placeholder);

    users.forEach(u => {
      const opt = document.createElement('option');
      opt.value = String(u.id);
      opt.textContent = u.username + (u.is_kicked ? ' (dismissed)' : '');
      els.userSelect.appendChild(opt);
    });

    els.userSelect.value = String(current || 0);
  }

  async function pollOnce(autoscroll) {
    const params = new URLSearchParams();
    params.set('since_id', String(state.sinceId || 0));

    if (state.role === 'admin' && state.targetUserId) {
      params.set('target_user_id', String(state.targetUserId));
    }

    const res = await api('/poll?' + params.toString(), { method: 'GET' });

    state.live = res.live || 0;
    renderLogoVisibility();

    if (state.role === 'admin') {
      setUsersDropdown(res.users || []);
      els.liveToggle.checked = state.live === 1;
    }

    if (res.kicked) {
      handleKicked();
      return;
    }

    const msgs = res.messages || [];
    if (msgs.length) {
      msgs.forEach(m => {
        addMessage(m);
        state.sinceId = Math.max(state.sinceId, m.id);
      });
      saveSession();

      if (autoscroll) scrollToBottom(true);
    }
  }

  function startPolling() {
    stopPolling();
    state.polling = setInterval(() => pollOnce(false).catch(() => {}), 1500);
  }

  function stopPolling() {
    if (state.polling) clearInterval(state.polling);
    state.polling = null;
  }

  async function logout() {
    try {
      await api('/logout', { method: 'POST', body: JSON.stringify({}) });
    } catch {}
    stopPolling();
    clearSession();
    exitChatUI();
  }

  async function sendTranscript() {
    const email = (els.transcriptEmail.value || '').trim();
    if (!email) {
      els.transcriptStatus.textContent = 'Enter an email address.';
      return;
    }

    const payload = { email };
    if (state.role === 'admin' && state.targetUserId) payload.target_user_id = state.targetUserId;

    els.transcriptStatus.textContent = 'Sending transcript...';

    try {
      const res = await api('/transcript', {
        method: 'POST',
        body: JSON.stringify(payload)
      });
      els.transcriptStatus.textContent = res.ok ? 'Transcript sent.' : 'Could not send transcript.';
    } catch {
      els.transcriptStatus.textContent = 'Could not send transcript.';
    }
  }

  async function adminKick(kick) {
    if (!state.targetUserId) {
      setStatus('Select a user first.');
      return;
    }
    await api('/admin/kick', {
      method: 'POST',
      body: JSON.stringify({ user_id: state.targetUserId, kick: kick ? 1 : 0 })
    });
    await pollOnce(false);
  }

  async function adminSetLive(live) {
    await api('/admin/live', {
      method: 'POST',
      body: JSON.stringify({ live: live ? 1 : 0 })
    });
    await pollOnce(false);
  }

  function bindEvents() {
    els.tabs.forEach(t => t.addEventListener('click', () => setRole(t.dataset.role)));

    els.loginBtn.addEventListener('click', () => login().catch(e => {
      showError((e && e.error) ? e.error : 'Login failed.');
    }));

    els.password.addEventListener('keydown', (ev) => {
      if (ev.key === 'Enter') els.loginBtn.click();
    });

    els.sendBtn.addEventListener('click', () => sendMessage().catch(() => {}));
    els.input.addEventListener('keydown', (ev) => {
      if (ev.key === 'Enter' && !ev.shiftKey) {
        ev.preventDefault();
        els.sendBtn.click();
      }
    });

    els.logoutBtn.addEventListener('click', () => logout());

    els.sendTranscriptBtn.addEventListener('click', () => sendTranscript());

    els.userSelect.addEventListener('change', async () => {
      state.targetUserId = parseInt(els.userSelect.value || '0', 10) || 0;
      state.sinceId = 0;
      els.messages.innerHTML = '';
      saveSession();
      await pollOnce(true);
      scrollToBottom(false);
    });

    els.kickBtn.addEventListener('click', () => adminKick(true).catch(() => {}));
    els.unkickBtn.addEventListener('click', () => adminKick(false).catch(() => {}));

    els.liveToggle.addEventListener('change', () => {
      adminSetLive(els.liveToggle.checked).catch(() => {});
    });
  }

  async function bootstrap() {
    initEls();
    bindEvents();

    // set initial live status
    try {
      const s = await api('/status', { method: 'GET' });
      state.live = s.live || 0;
      renderLogoVisibility();
    } catch {}

    // Try restore session
    if (loadSession()) {
      setRole(state.role);
      enterChatUI();
      renderLogoVisibility();
      await pollOnce(true).catch(() => {
        // session invalid
        clearSession();
        exitChatUI();
      });
      startPolling();
      scrollToBottom(false);
    } else {
      exitChatUI();
    }
  }

  document.addEventListener('DOMContentLoaded', bootstrap);
})();