(function () {
  function ready(fn) {
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', fn);
    } else {
      fn();
    }
  }

  function el(tag, attrs) {
    var n = document.createElement(tag);
    if (attrs) {
      Object.keys(attrs).forEach(function (k) {
        if (k === 'class') n.className = attrs[k];
        else if (k === 'text') n.textContent = attrs[k];
        else n.setAttribute(k, attrs[k]);
      });
    }
    for (var i = 2; i < arguments.length; i++) {
      var c = arguments[i];
      if (c == null) continue;
      if (typeof c === 'string') n.appendChild(document.createTextNode(c));
      else n.appendChild(c);
    }
    return n;
  }

  var config = (window.AIPostAdminChatConfig && typeof window.AIPostAdminChatConfig === 'object')
    ? window.AIPostAdminChatConfig
    : {};

  function apiFetch(path, opts) {
    opts = opts || {};
    var base = config.restBase ? String(config.restBase) : '/wp-json/';
    if (base && base.charAt(base.length - 1) !== '/') base += '/';
    var url = base + 'aipost/v1' + path;

    opts.headers = opts.headers || {};
    if (!opts.headers['Content-Type']) {
      opts.headers['Content-Type'] = 'application/json';
    }
    if (config.nonce) {
      opts.headers['X-WP-Nonce'] = config.nonce;
    }

    return fetch(url, opts).then(function (r) {
      var ct = '';
      try { ct = (r.headers && r.headers.get) ? (r.headers.get('content-type') || '') : ''; } catch (e) { ct = ''; }
      return r.text().then(function (text) {
        var bodyText = String(text == null ? '' : text);
        var trimmed = bodyText.replace(/^\uFEFF/, '').trim();
        var j = null;

        if (trimmed !== '') {
          try { j = JSON.parse(trimmed); } catch (e) { j = null; }
        }

        if (!j) {
          // 常见：REST 被拦截/重定向到登录页/Cloudflare/WAF 返回 HTML
          var prefix = trimmed.slice(0, 80);
          var looksHtml = prefix.charAt(0) === '<' || prefix.toLowerCase().indexOf('<html') !== -1;
          var hint = looksHtml ? '接口返回了 HTML（可能被重定向/权限不足/安全拦截/REST 被禁用）' : '接口未返回合法 JSON';
          var msg = hint + '：HTTP ' + r.status + (ct ? (' ' + ct) : '') + (prefix ? (' | ' + prefix) : '');
          throw new Error(msg);
        }

        if (!r.ok) {
          var msg2 = (j && (j.message || j.error)) ? (j.message || j.error) : ('HTTP ' + r.status);
          throw new Error(msg2);
        }

        return j;
      });
    });
  }

  function firstLineText(text) {
    text = String(text == null ? '' : text);
    // 仅保留第一行（第一句话/摘要），避免多行撑高卡片
    text = text.replace(/\r\n/g, '\n');
    var idx = text.indexOf('\n');
    if (idx >= 0) text = text.slice(0, idx);
    return text.trim();
  }

  function ensureUI() {
    var root = document.getElementById('aipost-admin-chat-root');
    if (!root) return null;

    function findTitleEl() {
      return document.querySelector('h1.wp-heading-inline')
        || document.querySelector('.wrap h1')
        || document.querySelector('h1');
    }

    function placeEntryToTitle(entryEl) {
      if (!entryEl) return false;
      var h1 = findTitleEl();
      if (!h1 || !h1.parentNode) return false;
      try {
        entryEl.classList.add('aipost-admin-chat-entry--title');
      } catch (e) {}

      try {
        h1.classList.add('aipost-admin-chat-page-title');
      } catch (e) {}

      // 使用专用标题栏容器让标题靠左、按钮靠右
      var titlebar = null;
      try {
        titlebar = h1.parentNode.querySelector('.aipost-admin-chat-titlebar');
      } catch (e) {}
      if (!titlebar) {
        try {
          titlebar = document.createElement('div');
          titlebar.className = 'aipost-admin-chat-titlebar';
          h1.parentNode.insertBefore(titlebar, h1);
          titlebar.appendChild(h1);
        } catch (e) {
          titlebar = null;
        }
      }

      // 插到标题右侧（紧跟 h1 后）
      try {
        if (titlebar) {
          titlebar.appendChild(entryEl);
        } else {
          h1.insertAdjacentElement('afterend', entryEl);
        }
      } catch (e) {
        if (entryEl.parentNode !== h1.parentNode) {
          h1.parentNode.insertBefore(entryEl, h1.nextSibling);
        }
      }

      try {
        root.style.display = 'none';
      } catch (e) {}
      return true;
    }

    function schedulePlaceToTitle(entryEl) {
      if (!entryEl) return;
      var ok = false;
      var tries = 0;

      function attempt() {
        if (ok) return;
        tries++;
        ok = placeEntryToTitle(entryEl);
        if (!ok && tries < 15) {
          setTimeout(attempt, 250);
        }
      }

      attempt();

      // 额外兜底：短时间监听标题异步渲染
      try {
        var obs = new MutationObserver(function () {
          if (ok) return;
          if (placeEntryToTitle(entryEl)) {
            ok = true;
            try { obs.disconnect(); } catch (e) {}
          }
        });
        obs.observe(document.body, { childList: true, subtree: true });
        setTimeout(function () {
          try { obs.disconnect(); } catch (e) {}
        }, 4000);
      } catch (e) {}
    }

    var btn = document.getElementById('aipost-admin-chat-open');
    var wrap = document.querySelector('.aipost-admin-chat-entry');
    if (!btn) {
      btn = el('button', { id: 'aipost-admin-chat-open', class: 'aipost-admin-chat-icon-btn', type: 'button' });
      try {
        btn.setAttribute('aria-label', '安妮');
        btn.setAttribute('title', '安妮');
      } catch (e) {}

      try {
        if (config && config.iconUrl) {
          var img = el('img', { class: 'aipost-admin-chat-icon', src: String(config.iconUrl), alt: '安妮' });
          btn.appendChild(img);
        } else {
          btn.textContent = '安妮';
        }
      } catch (e) {
        btn.textContent = '安妮';
      }
      wrap = el('div', { class: 'aipost-admin-chat-entry' }, btn);
      root.appendChild(wrap);
    }

    // 优先把入口按钮放到页面标题右侧
    try {
      if (wrap) {
        schedulePlaceToTitle(wrap);
      }
    } catch (e) {}

    var overlay = document.getElementById('aipost-admin-chat-overlay');
    var drawer = document.getElementById('aipost-admin-chat-drawer');

    function clamp(v, min, max) {
      return Math.max(min, Math.min(max, v));
    }

    function getMinMax() {
      var minW = parseInt((window.getComputedStyle(drawer).minWidth || '520'), 10) || 520;
      var minH = parseInt((window.getComputedStyle(drawer).minHeight || '420'), 10) || 420;
      var maxW = window.innerWidth - 48;
      var maxH = window.innerHeight - 140;
      return { minW: minW, minH: minH, maxW: Math.max(minW, maxW), maxH: Math.max(minH, maxH) };
    }

    function normalizeIntoViewport() {
      if (!drawer) return;
      var mm = getMinMax();
      var rect = drawer.getBoundingClientRect();
      var w = clamp(rect.width, mm.minW, mm.maxW);
      var h = clamp(rect.height, mm.minH, mm.maxH);
      var left = clamp(rect.left, 24, window.innerWidth - w - 24);
      var top = clamp(rect.top, 70, window.innerHeight - h - 70);
      drawer.style.width = w + 'px';
      drawer.style.height = h + 'px';
      drawer.style.left = left + 'px';
      drawer.style.top = top + 'px';
    }

    function centerDrawer() {
      if (!drawer) return;
      var mm = getMinMax();
      var w = clamp(drawer.offsetWidth || 980, mm.minW, mm.maxW);
      var h = clamp(drawer.offsetHeight || 640, mm.minH, mm.maxH);
      var left = Math.max(24, Math.round((window.innerWidth - w) / 2));
      var top = Math.max(70, Math.round((window.innerHeight - h) / 2));
      drawer.style.width = w + 'px';
      drawer.style.height = h + 'px';
      drawer.style.left = left + 'px';
      drawer.style.top = top + 'px';
    }

    function bindResizeHandles() {
      var handles = drawer ? drawer.querySelectorAll('.aipost-admin-chat-resize-handle') : [];
      if (!handles || !handles.length) return;

      function onDown(e) {
        var dir = (e.currentTarget && e.currentTarget.getAttribute('data-dir')) || '';
        if (!dir) return;
        e.preventDefault();

        normalizeIntoViewport();
        var startX = e.clientX;
        var startY = e.clientY;
        var rect = drawer.getBoundingClientRect();
        var startLeft = rect.left;
        var startTop = rect.top;
        var startW = rect.width;
        var startH = rect.height;
        var mm = getMinMax();

        function onMove(ev) {
          ev.preventDefault();
          var dx = ev.clientX - startX;
          var dy = ev.clientY - startY;
          var left = startLeft;
          var top = startTop;
          var w = startW;
          var h = startH;

          if (dir.indexOf('e') !== -1) { w = startW + dx; }
          if (dir.indexOf('s') !== -1) { h = startH + dy; }
          if (dir.indexOf('w') !== -1) { w = startW - dx; left = startLeft + dx; }
          if (dir.indexOf('n') !== -1) { h = startH - dy; top = startTop + dy; }

          w = clamp(w, mm.minW, mm.maxW);
          h = clamp(h, mm.minH, mm.maxH);
          left = clamp(left, 24, window.innerWidth - w - 24);
          top = clamp(top, 70, window.innerHeight - h - 70);

          drawer.style.width = w + 'px';
          drawer.style.height = h + 'px';
          drawer.style.left = left + 'px';
          drawer.style.top = top + 'px';
        }

        function onUp() {
          document.removeEventListener('mousemove', onMove);
          document.removeEventListener('mouseup', onUp);
        }

        document.addEventListener('mousemove', onMove);
        document.addEventListener('mouseup', onUp);
      }

      for (var i = 0; i < handles.length; i++) {
        handles[i].addEventListener('mousedown', onDown);
      }
    }

    function open() {
      overlay.classList.add('is-open');
      drawer.classList.add('is-open');
      centerDrawer();
      // 打开抽屉时主动加载模型列表，避免下拉框长期空白
      try { state.models = null; } catch (e) {}
      loadModels().catch(function (e) {
        setStatus('加载模型失败：' + (e && e.message ? e.message : 'unknown'), false);
      });
      loadSessions();
    }

    function close() {
      overlay.classList.remove('is-open');
      drawer.classList.remove('is-open');
    }

    btn.addEventListener('click', open);
    overlay.addEventListener('click', close);

    bindResizeHandles();
    window.addEventListener('resize', function () {
      if (drawer && drawer.classList.contains('is-open')) {
        normalizeIntoViewport();
      }
    });

    var closeBtn = document.getElementById('aipost-admin-chat-close');
    if (closeBtn) closeBtn.addEventListener('click', close);

    return { open: open, close: close };
  }

  var state = {
    sessions: [],
    activeSessionId: 0,
    models: null,
  };

  var DEFAULT_WELCOME_TEXT = '嗨，站长你好，我是你的专属ai助手安妮，有什么问题可以帮你呢？';

  function getSelectedModel() {
    var modelVal = '';
    try {
      var sel = document.getElementById('aipost-admin-chat-model');
      if (sel && sel.value) {
        modelVal = String(sel.value);
      }
    } catch (e) {}
    return modelVal;
  }

  function renderModelSelect(models) {
    var sel = document.getElementById('aipost-admin-chat-model');
    if (!sel) return;
    var options = (models && models.options && models.options.length) ? models.options : [];
    var defVal = (models && models.default) ? String(models.default) : '';

    sel.innerHTML = '';
    if (!options.length) {
      var opt0 = document.createElement('option');
      opt0.value = '';
      opt0.textContent = '账号默认';
      sel.appendChild(opt0);
      return;
    }

    options.forEach(function (o) {
      var v = (o && o.value != null) ? String(o.value) : '';
      var label = (o && o.label != null) ? String(o.label) : v;
      var opt = document.createElement('option');
      opt.value = v;
      opt.textContent = label;
      sel.appendChild(opt);
    });

    // 初次设置默认值；后续用户切换不主动覆盖
    if (sel.value === '' && defVal) {
      try { sel.value = defVal; } catch (e) {}
    }
  }

  function deleteSession(sessionId) {
    if (!sessionId) return;
    function ajaxDelete() {
      if (!config.ajaxUrl || !config.ajaxNonce) {
        return Promise.reject(new Error('missing_ajax_config'));
      }
      var params = new URLSearchParams();
      params.set('action', 'aipost_admin_chat_session_delete');
      params.set('_ajax_nonce', config.ajaxNonce);
      params.set('session_id', String(sessionId));
      return fetch(config.ajaxUrl, {
        method: 'POST',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
        body: params.toString(),
        credentials: 'same-origin'
      }).then(function (r) {
        return r.text().then(function (text) {
          var trimmed = String(text == null ? '' : text).replace(/^\uFEFF/, '').trim();
          var j = null;
          try { j = trimmed ? JSON.parse(trimmed) : null; } catch (e) { j = null; }
          if (!j) {
            var prefix = trimmed.slice(0, 80);
            throw new Error('AJAX 接口未返回合法 JSON：HTTP ' + r.status + (prefix ? (' | ' + prefix) : ''));
          }
          if (!r.ok || j.success === false) {
            var msg = (j && j.data && j.data.message) ? String(j.data.message) : ('HTTP ' + r.status);
            throw new Error(msg);
          }
          return j.data && typeof j.data === 'object' ? j.data : j;
        });
      });
    }

    apiFetch('/chat/sessions/' + sessionId, {
      method: 'DELETE',
    }).catch(function () {
      return ajaxDelete();
    }).then(function () {
      if (state.activeSessionId === sessionId) {
        state.activeSessionId = 0;
      }
      return loadSessions();
    }).catch(function (e) {
      setStatus('删除会话失败：' + (e && e.message ? e.message : 'unknown'), false);
    });
  }

  function renderSessions() {
    var list = document.getElementById('aipost-admin-chat-sessions');
    if (!list) return;

    list.innerHTML = '';

    var header = el('div', { class: 'aipost-admin-chat-sessions-header' });
    var title = el('div', { class: 'aipost-admin-chat-sessions-title', text: '会话' });
    var newBtn = el('button', { type: 'button', class: 'button', text: '新建' });
    header.appendChild(title);
    header.appendChild(newBtn);
    list.appendChild(header);

    newBtn.addEventListener('click', function () {
      createSession();
    });

    if (!state.sessions.length) {
      list.appendChild(el('div', { class: 'aipost-admin-chat-empty', text: '暂无会话' }));
      return;
    }

    state.sessions.forEach(function (s) {
      var item = el('div', { class: 'aipost-admin-chat-session-item' + (s.id === state.activeSessionId ? ' is-active' : '') });
      var row = el('div', { class: 'aipost-admin-chat-session-row' });
      var left = el('div', { class: 'aipost-admin-chat-session-left' });
      var t = el('div', { class: 'aipost-admin-chat-session-title', text: s.title || ('会话 #' + s.id) });
      var subText = firstLineText(s.last_message_excerpt || '');
      var sub = el('div', { class: 'aipost-admin-chat-session-sub', text: subText });
      left.appendChild(t);
      left.appendChild(sub);

      var actions = el('div', { class: 'aipost-admin-chat-session-actions' });
      var delBtn = el('button', { type: 'button', class: 'aipost-admin-chat-session-delete', text: '🗑' });
      delBtn.addEventListener('click', function (ev) {
        ev.preventDefault();
        ev.stopPropagation();
        deleteSession(s.id);
      });
      actions.appendChild(delBtn);

      row.appendChild(left);
      row.appendChild(actions);
      item.appendChild(row);
      item.addEventListener('click', function () {
        setActiveSession(s.id);
      });
      list.appendChild(item);
    });
  }

  function renderMessages(messages, opts) {
    var box = document.getElementById('aipost-admin-chat-messages');
    if (!box) return;

    opts = opts || {};

    box.innerHTML = '';

    if ((!messages || !messages.length) && !opts.suppressWelcome) {
      var row0 = el('div', { class: 'aipost-admin-chat-msg assistant' });
      var bubble0 = el('div', { class: 'aipost-admin-chat-bubble' });
      bubble0.textContent = DEFAULT_WELCOME_TEXT;
      row0.appendChild(bubble0);
      box.appendChild(row0);
      box.scrollTop = box.scrollHeight;
      return;
    }

    (messages || []).forEach(function (m) {
      var cls = (m.role === 'assistant') ? 'assistant' : 'user';
      var row = el('div', { class: 'aipost-admin-chat-msg ' + cls });
      var bubble = el('div', { class: 'aipost-admin-chat-bubble' });
      var content = m.content || '';
      if (m.role === 'assistant') {
        content = sanitizeAssistantText(content);
      }
      bubble.textContent = content;
      row.appendChild(bubble);
      box.appendChild(row);
    });
    box.scrollTop = box.scrollHeight;
  }

  function sanitizeAssistantText(text) {
    text = String(text == null ? '' : text);
    // 清洗部分模型返回的 Markdown 标题符号：仅处理行首，避免影响正常内容
    // 例："### 标题" -> "标题"
    return text.replace(/^\s{0,3}#{1,6}\s+/gm, '');
  }

  function appendMessage(role, content) {
    var box = document.getElementById('aipost-admin-chat-messages');
    if (!box) return null;
    var cls = (role === 'assistant') ? 'assistant' : 'user';
    var row = el('div', { class: 'aipost-admin-chat-msg ' + cls });
    var bubble = el('div', { class: 'aipost-admin-chat-bubble' });
    var out = content || '';
    if (role === 'assistant') {
      out = sanitizeAssistantText(out);
    }
    bubble.textContent = out;
    row.appendChild(bubble);
    box.appendChild(row);
    box.scrollTop = box.scrollHeight;
    return row;
  }

  function setBubbleText(rowEl, text) {
    if (!rowEl) return;
    var bubble = rowEl.querySelector('.aipost-admin-chat-bubble');
    if (!bubble) return;
    var out = text || '';
    try {
      if (rowEl.classList && rowEl.classList.contains('assistant')) {
        out = sanitizeAssistantText(out);
      }
    } catch (e) {}
    bubble.textContent = out;
    var box = document.getElementById('aipost-admin-chat-messages');
    if (box) box.scrollTop = box.scrollHeight;
  }

  function streamSendMessage(sessionId, text, modelVal, pendingEl) {
    if (!config.ajaxUrl || !config.ajaxNonce) {
      return Promise.reject(new Error('missing_ajax_config'));
    }

    var params = new URLSearchParams();
    params.set('action', 'aipost_admin_chat_stream');
    params.set('_ajax_nonce', config.ajaxNonce);
    params.set('session_id', String(sessionId));
    params.set('content', text);
    if (modelVal) params.set('model', modelVal);

    return fetch(config.ajaxUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
      },
      body: params.toString(),
      credentials: 'same-origin'
    }).then(function (res) {
      if (!res.ok) {
        throw new Error('http_' + res.status);
      }
      if (!res.body || !window.ReadableStream) {
        throw new Error('stream_unsupported');
      }

      var reader = res.body.getReader();
      var decoder = new TextDecoder('utf-8');
      var buf = '';
      var full = '';

      function pump() {
        return reader.read().then(function (r) {
          if (r.done) return;
          buf += decoder.decode(r.value, { stream: true });

          var parts = buf.split('\n\n');
          buf = parts.pop() || '';
          parts.forEach(function (chunk) {
            chunk = String(chunk || '');
            var lines = chunk.split('\n');
            lines.forEach(function (ln) {
              ln = String(ln || '').trim();
              if (ln.indexOf('data:') !== 0) return;
              var jsonStr = ln.slice(5).trim();
              if (!jsonStr) return;
              var obj = null;
              try { obj = JSON.parse(jsonStr); } catch (e) { return; }
              if (!obj || obj.ok === false) {
                throw new Error(obj && obj.error ? String(obj.error) : 'stream_error');
              }
              if (obj.type === 'delta' && typeof obj.delta === 'string') {
                full += obj.delta;
                setBubbleText(pendingEl, full);
              }
            });
          });

          return pump();
        });
      }

      return pump().then(function () {
        return full;
      });
    });
  }

  function loadModels() {
    if (state.models) return Promise.resolve(state.models);
    function setModelsFromRes(res) {
      state.models = (res && res.models) ? res.models : null;
      renderModelSelect(state.models);
      return state.models;
    }

    function ajaxFetchModels() {
      if (!config.ajaxUrl || !config.ajaxNonce) {
        return Promise.reject(new Error('missing_ajax_config'));
      }
      var params = new URLSearchParams();
      params.set('action', 'aipost_admin_chat_models');
      params.set('_ajax_nonce', config.ajaxNonce);
      return fetch(config.ajaxUrl, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
        },
        body: params.toString(),
        credentials: 'same-origin'
      }).then(function (r) {
        return r.text().then(function (text) {
          var trimmed = String(text == null ? '' : text).replace(/^\uFEFF/, '').trim();
          var j = null;
          try { j = trimmed ? JSON.parse(trimmed) : null; } catch (e) { j = null; }
          if (!j) {
            var prefix = trimmed.slice(0, 80);
            throw new Error('AJAX 接口未返回合法 JSON：HTTP ' + r.status + (prefix ? (' | ' + prefix) : ''));
          }
          if (!r.ok || j.success === false) {
            var msg = (j && j.data && j.data.message) ? String(j.data.message) : ('HTTP ' + r.status);
            throw new Error(msg);
          }
          // wp_send_json_success: { success: true, data: { ok:true, models:{...} } }
          var data = j.data && typeof j.data === 'object' ? j.data : j;
          return data;
        });
      });
    }

    return apiFetch('/chat/models')
      .then(setModelsFromRes)
      .catch(function () {
        return ajaxFetchModels().then(setModelsFromRes);
      });
  }

  function loadSessions() {
    function ajaxFetchSessions() {
      if (!config.ajaxUrl || !config.ajaxNonce) {
        return Promise.reject(new Error('missing_ajax_config'));
      }
      var params = new URLSearchParams();
      params.set('action', 'aipost_admin_chat_sessions');
      params.set('_ajax_nonce', config.ajaxNonce);
      return fetch(config.ajaxUrl, {
        method: 'POST',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
        body: params.toString(),
        credentials: 'same-origin'
      }).then(function (r) {
        return r.text().then(function (text) {
          var trimmed = String(text == null ? '' : text).replace(/^\uFEFF/, '').trim();
          var j = null;
          try { j = trimmed ? JSON.parse(trimmed) : null; } catch (e) { j = null; }
          if (!j) {
            var prefix = trimmed.slice(0, 80);
            throw new Error('AJAX 接口未返回合法 JSON：HTTP ' + r.status + (prefix ? (' | ' + prefix) : ''));
          }
          if (!r.ok || j.success === false) {
            var msg = (j && j.data && j.data.message) ? String(j.data.message) : ('HTTP ' + r.status);
            throw new Error(msg);
          }
          return j.data && typeof j.data === 'object' ? j.data : j;
        });
      });
    }

    return apiFetch('/chat/sessions')
      .catch(function () { return ajaxFetchSessions(); })
      .then(function (res) {
        state.sessions = (res && res.sessions) ? res.sessions : [];
        if (!state.activeSessionId && state.sessions.length) {
          state.activeSessionId = state.sessions[0].id;
          loadMessages(state.activeSessionId);
        }
        renderSessions();
        return state.sessions;
      }).catch(function (e) {
        renderSessions();
        setStatus('加载会话失败：' + (e && e.message ? e.message : 'unknown'), false);
      });
  }

  function loadMessages(sessionId) {
    if (!sessionId) return;
    function ajaxFetchMessages() {
      if (!config.ajaxUrl || !config.ajaxNonce) {
        return Promise.reject(new Error('missing_ajax_config'));
      }
      var params = new URLSearchParams();
      params.set('action', 'aipost_admin_chat_messages');
      params.set('_ajax_nonce', config.ajaxNonce);
      params.set('session_id', String(sessionId));
      return fetch(config.ajaxUrl, {
        method: 'POST',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
        body: params.toString(),
        credentials: 'same-origin'
      }).then(function (r) {
        return r.text().then(function (text) {
          var trimmed = String(text == null ? '' : text).replace(/^\uFEFF/, '').trim();
          var j = null;
          try { j = trimmed ? JSON.parse(trimmed) : null; } catch (e) { j = null; }
          if (!j) {
            var prefix = trimmed.slice(0, 80);
            throw new Error('AJAX 接口未返回合法 JSON：HTTP ' + r.status + (prefix ? (' | ' + prefix) : ''));
          }
          if (!r.ok || j.success === false) {
            var msg = (j && j.data && j.data.message) ? String(j.data.message) : ('HTTP ' + r.status);
            throw new Error(msg);
          }
          return j.data && typeof j.data === 'object' ? j.data : j;
        });
      });
    }

    return apiFetch('/chat/sessions/' + sessionId + '/messages')
      .catch(function () { return ajaxFetchMessages(); })
      .then(function (res) {
        renderMessages(res && res.messages ? res.messages : []);
      }).catch(function (e) {
        renderMessages([], { suppressWelcome: true });
        setStatus('加载消息失败：' + (e && e.message ? e.message : 'unknown'), false);
      });
  }

  function setActiveSession(sessionId) {
    state.activeSessionId = sessionId;
    renderSessions();
    loadMessages(sessionId);
  }

  function createSession() {
    function ajaxCreateSession(modelVal) {
      if (!config.ajaxUrl || !config.ajaxNonce) {
        return Promise.reject(new Error('missing_ajax_config'));
      }
      var params = new URLSearchParams();
      params.set('action', 'aipost_admin_chat_session_create');
      params.set('_ajax_nonce', config.ajaxNonce);
      params.set('title', '');
      if (modelVal) params.set('model', String(modelVal));
      return fetch(config.ajaxUrl, {
        method: 'POST',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
        body: params.toString(),
        credentials: 'same-origin'
      }).then(function (r) {
        return r.text().then(function (text) {
          var trimmed = String(text == null ? '' : text).replace(/^\uFEFF/, '').trim();
          var j = null;
          try { j = trimmed ? JSON.parse(trimmed) : null; } catch (e) { j = null; }
          if (!j) {
            var prefix = trimmed.slice(0, 80);
            throw new Error('AJAX 接口未返回合法 JSON：HTTP ' + r.status + (prefix ? (' | ' + prefix) : ''));
          }
          if (!r.ok || j.success === false) {
            var msg = (j && j.data && j.data.message) ? String(j.data.message) : ('HTTP ' + r.status);
            throw new Error(msg);
          }
          return j.data && typeof j.data === 'object' ? j.data : j;
        });
      });
    }

    return loadModels().then(function (models) {
      var modelVal = getSelectedModel();
      if (!modelVal) {
        try {
          if (models && models.default) modelVal = String(models.default);
        } catch (e) {}
      }

      return apiFetch('/chat/sessions', {
        method: 'POST',
        body: JSON.stringify({ title: '', model: modelVal }),
      }).catch(function () {
        return ajaxCreateSession(modelVal);
      });
    }).then(function (res) {
      if (res && res.session && res.session.id) {
        var newId = res.session.id;
        // 立即切换到新会话：右侧面板立刻清空/显示新会话上下文
        state.activeSessionId = newId;
        renderSessions();
        renderMessages([]);
        // 再异步刷新会话列表与消息
        return loadSessions().then(function () {
          return loadMessages(newId);
        });
      }
    }).catch(function (e) {
      setStatus('新建会话失败：' + (e && e.message ? e.message : 'unknown'), false);
    });
  }

  function sendMessage() {
    var input = document.getElementById('aipost-admin-chat-input');
    if (!input) return;
    var text = String(input.value || '').trim();
    if (!text) return;

    var sid = state.activeSessionId;
    if (!sid) {
      createSession().then(function () {
        sendMessage();
      });
      return;
    }

    input.value = '';
    // 乐观渲染：先把用户消息立即显示
    appendMessage('user', text);
    // 占位：助手回复中
    var pendingEl = appendMessage('assistant', '正在回复...');
    setStatus('发送中...', true);

    var modelVal = getSelectedModel();

    // 优先：流式输出
    streamSendMessage(sid, text, modelVal, pendingEl).then(function () {
      setStatus('', true);
      return loadSessions().then(function () { return loadMessages(sid); });
    }).catch(function () {
      // 回退：非流式 REST
      function ajaxSend() {
        if (!config.ajaxUrl || !config.ajaxNonce) {
          return Promise.reject(new Error('missing_ajax_config'));
        }
        var params = new URLSearchParams();
        params.set('action', 'aipost_admin_chat_message_send');
        params.set('_ajax_nonce', config.ajaxNonce);
        params.set('session_id', String(sid));
        params.set('content', String(text));
        if (modelVal) params.set('model', String(modelVal));
        return fetch(config.ajaxUrl, {
          method: 'POST',
          headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
          body: params.toString(),
          credentials: 'same-origin'
        }).then(function (r) {
          return r.text().then(function (t) {
            var trimmed = String(t == null ? '' : t).replace(/^\uFEFF/, '').trim();
            var j = null;
            try { j = trimmed ? JSON.parse(trimmed) : null; } catch (e) { j = null; }
            if (!j) {
              var prefix = trimmed.slice(0, 80);
              throw new Error('AJAX 接口未返回合法 JSON：HTTP ' + r.status + (prefix ? (' | ' + prefix) : ''));
            }
            if (!r.ok || j.success === false) {
              var msg = (j && j.data && j.data.message) ? String(j.data.message) : ('HTTP ' + r.status);
              throw new Error(msg);
            }
            return j.data && typeof j.data === 'object' ? j.data : j;
          });
        });
      }

      apiFetch('/chat/sessions/' + sid + '/messages', {
        method: 'POST',
        body: JSON.stringify({ content: text, model: modelVal || undefined }),
      }).catch(function () {
        return ajaxSend();
      }).then(function () {
        setStatus('', true);
        if (pendingEl && pendingEl.parentNode) {
          pendingEl.parentNode.removeChild(pendingEl);
        }
        return loadSessions().then(function () { return loadMessages(sid); });
      }).catch(function (e) {
        if (pendingEl) {
          try {
            var b = pendingEl.querySelector('.aipost-admin-chat-bubble');
            if (b) { b.textContent = '发送失败'; }
          } catch (err) {}
        }
        setStatus('发送失败：' + (e && e.message ? e.message : 'unknown'), false);
      });
    });
  }

  function setStatus(text, ok) {
    var elx = document.getElementById('aipost-admin-chat-status');
    if (!elx) return;
    elx.textContent = text || '';
    elx.className = ok ? 'ok' : 'bad';
  }

  function bindComposer() {
    var btn = document.getElementById('aipost-admin-chat-send');
    var input = document.getElementById('aipost-admin-chat-input');
    if (btn) btn.addEventListener('click', sendMessage);
    if (input) {
      input.addEventListener('keydown', function (e) {
        if (e.key === 'Enter' && !e.shiftKey) {
          e.preventDefault();
          sendMessage();
        }
      });
    }
  }

  ready(function () {
    var ui = ensureUI();
    if (!ui) return;
    bindComposer();
  });
})();
