/**
 * 审批中心角标自动更新 - 模拟数据变化测试脚本
 * 
 * 使用方法：
 * 1. 打开审批中心页面（/app/approve_workflow/instances/grid/inbox 等）
 * 2. 打开浏览器控制台 (F12 → Console)
 * 3. 复制粘贴本脚本内容到控制台并回车
 * 4. 等待测试完成，查看报告
 * 
 * 测试原理：
 * - 拦截 /api/.../workflow/nav 的 API 响应
 * - 每轮将 inbox 角标值篡改为递增值（模拟收到新审批单 +1）
 * - 模拟完整 socket 流程：先 Service reload，再 Tree reload（与 socket.client.js 一致）
 * - 等待 UI 更新后，读取 DOM 中角标显示值
 * - 第一轮失败即停止（快速定位问题）
 */
(async function testBadgeUpdate() {
  'use strict';

  const TOTAL_ROUNDS = 10;       // 总测试轮数
  const STOP_ON_FAIL = true;     // 第一次失败即停止

  console.log('%c=== 角标更新自动化测试（模拟数据变化）===', 'color: blue; font-size: 16px; font-weight: bold;');
  console.log(`总测试轮数: ${TOTAL_ROUNDS}, 失败即停: ${STOP_ON_FAIL}`);
  console.log('');

  // 检查前置条件
  const menuEl = document.querySelector('.approval-tree-menu');

  if (!menuEl) { console.error('❌ 未找到 .approval-tree-menu 组件'); return; }
  console.log('✅ 前置条件检查通过: .approval-tree-menu 组件存在');

  // 状态
  let roundCounter = 0;
  let baseInboxTag = null;
  let expectedInboxTag = null;
  let actualApiInboxTag = null;
  let apiCallCount = 0;
  let fetchInitedCount = 0;

  // ---- 监听日志 ----
  const origConsoleLog = console.log;
  const fetchInitedLogs = [];

  // ======== 篡改 options 的通用函数 ========
  function tamperOptions(json, source) {
    if (!(json && json.data && Array.isArray(json.data.options))) return null;
    const inboxIdx = json.data.options.findIndex(opt =>
      opt.value && opt.value.includes('inbox') && opt.hasOwnProperty('tag')
    );
    if (inboxIdx < 0) return null;

    if (baseInboxTag === null) {
      baseInboxTag = json.data.options[inboxIdx].tag;
      origConsoleLog.call(console, `%c[${source}拦截] 基准 inbox 角标: ${baseInboxTag}`, 'color: orange;');
    }

    const newTag = baseInboxTag + roundCounter;
    json.data.options[inboxIdx].tag = newTag;

    if (Array.isArray(json.data.options[inboxIdx].children)) {
      json.data.options[inboxIdx].children.forEach(child => {
        if (child.hasOwnProperty('tag')) {
          child.tag = (child.tag || 0) + roundCounter;
        }
      });
    }

    actualApiInboxTag = newTag;
    expectedInboxTag = newTag;
    origConsoleLog.call(console, `%c[${source}拦截] 第${roundCounter}轮: 篡改 inbox tag → ${newTag}`, 'color: orange;');
    return json;
  }

  // ======== 拦截 fetch，篡改 API 响应 ========
  const originalFetch = window.fetch;
  window.fetch = async function (...args) {
    const response = await originalFetch.apply(this, args);
    const url = typeof args[0] === 'string' ? args[0] : (args[0] && args[0].url) || '';

    if (url.includes('/workflow/nav')) {
      apiCallCount++;
      try {
        const cloned = response.clone();
        const json = await cloned.json();
        const tampered = tamperOptions(json, 'fetch');
        if (tampered) {
          return new Response(JSON.stringify(tampered), {
            status: response.status, statusText: response.statusText, headers: response.headers
          });
        }
      } catch (e) {
        origConsoleLog.call(console, '%c[fetch拦截] 解析失败:', 'color: red;', e);
      }
    }
    return response;
  };

  // ======== 拦截 XMLHttpRequest，用 getter 篡改响应（在 axios 读取前拦截）========
  const XHR = XMLHttpRequest.prototype;
  const origXHROpen = XHR.open;
  const origXHRSend = XHR.send;
  const xhrUrlMap = new WeakMap();
  const origResponseTextDesc = Object.getOwnPropertyDescriptor(XMLHttpRequest.prototype, 'responseText');
  const origResponseDesc = Object.getOwnPropertyDescriptor(XMLHttpRequest.prototype, 'response');

  XHR.open = function (method, url) {
    xhrUrlMap.set(this, { url: String(url) });
    return origXHROpen.apply(this, arguments);
  };

  XHR.send = function () {
    const info = xhrUrlMap.get(this);
    if (info && info.url && info.url.includes('/workflow/nav')) {
      const xhr = this;
      let _tamperedText = null;
      let _processed = false;

      // 用 getter 拦截 responseText —— 在 axios 读取时触发篡改
      Object.defineProperty(xhr, 'responseText', {
        get: function () {
          const realText = origResponseTextDesc.get.call(this);
          if (this.readyState === 4 && !_processed && realText) {
            _processed = true;
            apiCallCount++;
            try {
              const json = JSON.parse(realText);
              const result = tamperOptions(json, 'XHR');
              if (result) {
                _tamperedText = JSON.stringify(result);
              }
            } catch (e) {
              origConsoleLog.call(console, '%c[XHR拦截] 解析失败:', 'color: red;', e);
            }
          }
          return _tamperedText || realText;
        },
        configurable: true
      });

      // 同步拦截 response 属性
      Object.defineProperty(xhr, 'response', {
        get: function () {
          // 触发 responseText 的篡改逻辑
          const text = xhr.responseText;
          if (xhr.responseType === '' || xhr.responseType === 'text') {
            return text;
          }
          if (xhr.responseType === 'json' && _tamperedText) {
            try { return JSON.parse(_tamperedText); } catch (e) { }
          }
          return origResponseDesc.get.call(this);
        },
        configurable: true
      });
    }
    return origXHRSend.apply(this, arguments);
  };

  // ======== DOM 读取 ========
  function findBadgeElements() {
    return menuEl.querySelectorAll('.ant-badge-count');
  }

  function getInboxBadgeFromDOM() {
    const badgeEls = findBadgeElements();
    if (badgeEls.length === 0) return null;
    const text = badgeEls[0].textContent.trim();
    const num = parseInt(text, 10);
    return isNaN(num) ? null : num;
  }

  function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  // ======== 执行测试 ========
  const results = [];

  // 初始化：获取基准值（模拟完整 socket 流程：nav reload + tree reload）
  origConsoleLog.call(console, '%c[初始化] 获取基准角标值...', 'color: orange;');
  roundCounter = 0;
  window.postMessage({ type: "approval-tree-menu:reload" }, "*");
  await sleep(4000);
  const initDom = getInboxBadgeFromDOM();
  origConsoleLog.call(console, `%c[初始化] 基准值: API=${baseInboxTag}, DOM=${initDom}, fetchInited=${fetchInitedCount}次`, 'color: orange;');
  
  if (baseInboxTag === null) {
    console.error('❌ 未能获取基准值，API 请求未被拦截（fetch 和 XHR 均未捕获）');
    window.fetch = originalFetch;
    XHR.open = origXHROpen;
    XHR.send = origXHRSend;
    return;
  }
  origConsoleLog.call(console, '');

  let stopped = false;
  for (let round = 1; round <= TOTAL_ROUNDS; round++) {
    roundCounter = round;
    actualApiInboxTag = null;
    expectedInboxTag = baseInboxTag + round;
    const apiCountBefore = apiCallCount;
    const fetchInitedBefore = fetchInitedCount;

    origConsoleLog.call(console, `%c[第 ${round}/${TOTAL_ROUNDS} 轮]`, 'color: #888; font-weight: bold;', 
      `期望角标: ${baseInboxTag} + ${round} = ${expectedInboxTag}`);

    // 触发刷新
    window.postMessage({ type: "approval-tree-menu:reload" }, "*");
    await sleep(3000);  // 等待 API 返回 + React 重新渲染

    // 3. 读取结果
    const apiCalls = apiCallCount - apiCountBefore;
    const fetchInitedFired = fetchInitedCount - fetchInitedBefore;
    const domValue = getInboxBadgeFromDOM();
    const pass = domValue === expectedInboxTag;

    const result = {
      round,
      apiCalls,
      fetchInited: fetchInitedFired,
      expected: expectedInboxTag,
      apiActual: actualApiInboxTag,
      dom: domValue,
      pass
    };
    results.push(result);

    const icon = pass ? '✅' : '❌';
    const color = pass ? 'color: green;' : 'color: red; font-weight: bold;';
    origConsoleLog.call(console,
      `${icon} %c第${round}轮:`,
      color,
      `API=${apiCalls}次`,
      `fetchInited=${fetchInitedFired}次`,
      `期望=${expectedInboxTag}`,
      `DOM=${domValue}`,
      pass ? '通过' : `失败(差${expectedInboxTag - domValue})`
    );

    if (!pass && STOP_ON_FAIL) {
      origConsoleLog.call(console, '%c⛔ 首次失败，停止测试', 'color: red; font-size: 14px; font-weight: bold;');
      origConsoleLog.call(console, '诊断信息:');
      origConsoleLog.call(console, '  fetchInited事件日志:', fetchInitedLogs.length > 0 ? fetchInitedLogs : '无(事件可能未触发)');
      origConsoleLog.call(console, '  fetchInited累计次数:', fetchInitedCount);
      origConsoleLog.call(console, '  API篡改后值:', actualApiInboxTag);
      origConsoleLog.call(console, '  DOM当前值:', domValue);
      origConsoleLog.call(console, '  DOM全部角标:', Array.from(findBadgeElements()).map(el => el.textContent.trim()));
      stopped = true;
      break;
    }

    if (round < TOTAL_ROUNDS) {
      await sleep(500);
    }
  }

  // 恢复
  window.fetch = originalFetch;
  XHR.open = origXHROpen;
  XHR.send = origXHRSend;

  // 报告
  const passed = results.filter(r => r.pass).length;
  const failed = results.filter(r => !r.pass).length;

  console.log('');
  console.log('%c=== 测试报告（模拟数据变化）===', 'color: blue; font-size: 16px; font-weight: bold;');
  console.log(`完成轮数: ${results.length}/${TOTAL_ROUNDS}${stopped ? ' (提前停止)' : ''}`);
  console.log(`基准角标: ${baseInboxTag}`);
  console.log(`通过: ${passed} ✅`);
  console.log(`失败: ${failed} ❌`);
  console.log(`%c成功率: ${(passed / results.length * 100).toFixed(1)}%`,
    failed === 0 ? 'color: green; font-size: 14px; font-weight: bold;' : 'color: red; font-size: 14px; font-weight: bold;');

  console.log('');
  console.log('%c详细结果:', 'font-weight: bold;');
  console.table(results.map(r => ({
    '轮次': r.round,
    'API次数': r.apiCalls,
    'fetchInited': r.fetchInited,
    '期望角标': r.expected,
    'DOM角标': r.dom,
    '结果': r.pass ? '✅通过' : '❌失败'
  })));

  return { passed, failed, total: results.length, rate: (passed / results.length * 100).toFixed(1) + '%' };
})();