// 插件主脚本：所有页面、工具逻辑和降级策略均内置；公网 IP/测速/DNS 泄漏等必须依赖远端观测点的项目才通过授权 HTTP 探测。
const $ = (id) => document.getElementById(id);
const state = {
  diagnostics: null,
  publicIp: null,
  trace: null,
  browser: {},
  webrtc: [],
  dnsProbe: null,
  latency: {},
  speed: null,
  lookup: null,
  checks: {},
  startedAt: null
};

const endpoints = {
  ipApis: [
    { name: "ipapi.co", url: "https://ipapi.co/json/" },
    { name: "ipwho.is", url: "https://ipwho.is/" },
    { name: "ip.sb", url: "https://api.ip.sb/geoip" }
  ],
  ipv4: "https://api.ipify.org?format=json",
  ipv6: "https://api64.ipify.org?format=json",
  trace: "https://speed.cloudflare.com/cdn-cgi/trace",
  speedDown: "https://speed.cloudflare.com/__down?bytes=1000000",
  speedUp: "https://speed.cloudflare.com/__up",
  doh: "https://cloudflare-dns.com/dns-query",
  rdapIp: "https://rdap.org/ip/",
  rdapDomain: "https://rdap.org/domain/",
  mac: "https://api.macvendors.com/"
};

const macVendors = {
  "001A2B": "Ayecom Technology",
  "001B63": "Apple",
  "001C42": "Parallels",
  "002248": "Microsoft",
  "005056": "VMware",
  "080027": "PCS Systemtechnik / VirtualBox",
  "3C5A37": "Google",
  "F4F5D8": "Google",
  "D850E6": "ASUSTek",
  "FCFBFB": "Cisco",
  "B827EB": "Raspberry Pi"
};

function escapeHtml(value) {
  return String(value ?? "")
    .replaceAll("&", "&amp;")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;")
    .replaceAll('"', "&quot;")
    .replaceAll("'", "&#039;");
}

function setBadge(id, status, text) {
  const el = $(id);
  if (!el) return;
  el.className = `badge ${status}`;
  el.textContent = text;
}

function setFacts(id, rows) {
  $(id).innerHTML = rows
    .map(([key, value]) => `<dt>${escapeHtml(key)}</dt><dd>${escapeHtml(value || "--")}</dd>`)
    .join("");
}

function setMetrics(id, rows) {
  $(id).innerHTML = rows
    .map(([key, value, tone = ""]) => `
      <div class="metric">
        <span>${escapeHtml(key)}</span>
        <strong class="${tone ? `${tone}Text` : ""}">${escapeHtml(value || "--")}</strong>
      </div>`)
    .join("");
}

function setChecks(id, rows) {
  $(id).innerHTML = rows
    .map(([key, value, tone = ""]) => `
      <div class="checkItem">
        <span>${escapeHtml(key)}</span>
        <strong class="${tone ? `${tone}Text` : ""}">${escapeHtml(value || "--")}</strong>
      </div>`)
    .join("");
}

function setOutput(id, value) {
  $(id).textContent = typeof value === "string" ? value : JSON.stringify(value, null, 2);
}

function flatten(values) {
  return [...new Set((values || []).flat().filter(Boolean))];
}

function activeInterfaces() {
  return (state.diagnostics?.interfaces || []).filter((item) => item.status === "Up");
}

function shortJson(value) {
  return JSON.stringify(value, null, 2)
    .replaceAll("\\u0022", "\"")
    .slice(0, 6000);
}

function parseJson(content) {
  try {
    return JSON.parse(content);
  } catch {
    return null;
  }
}

async function bridgeFetch(request) {
  const response = await window.ymhut.http.fetch(request);
  if (!response.ok) {
    throw new Error(`HTTP ${response.status}`);
  }
  return response;
}

async function fetchJson(url, options = {}) {
  const response = await bridgeFetch({ url, headers: options.headers, method: options.method, body: options.body });
  return { data: parseJson(response.content), response };
}

async function firstSuccessful(tasks) {
  const errors = [];
  for (const task of tasks) {
    try {
      const value = await task();
      return value;
    } catch (error) {
      errors.push(error.message);
    }
  }
  throw new Error(errors.join("; "));
}

function normalizeIpInfo(source, data) {
  if (!data) return null;
  if (source === "ipapi.co") {
    return {
      source,
      ip: data.ip,
      version: data.version,
      city: data.city,
      region: data.region,
      country: data.country_name || data.country,
      countryCode: data.country_code,
      timezone: data.timezone,
      latitude: data.latitude,
      longitude: data.longitude,
      asn: data.asn,
      isp: data.org,
      postal: data.postal,
      raw: data
    };
  }
  if (source === "ipwho.is") {
    return {
      source,
      ip: data.ip,
      version: data.type,
      city: data.city,
      region: data.region,
      country: data.country,
      countryCode: data.country_code,
      timezone: data.timezone?.id,
      latitude: data.latitude,
      longitude: data.longitude,
      asn: data.connection?.asn ? `AS${data.connection.asn}` : "",
      isp: data.connection?.isp || data.connection?.org,
      postal: data.postal,
      raw: data
    };
  }
  return {
    source,
    ip: data.ip || data.address,
    version: data.version,
    city: data.city,
    region: data.region,
    country: data.country,
    countryCode: data.country_code,
    timezone: data.timezone,
    latitude: data.latitude,
    longitude: data.longitude,
    asn: data.asn,
    isp: data.organization || data.isp,
    postal: data.postal_code,
    raw: data
  };
}

function parseTrace(text) {
  const rows = {};
  String(text || "").split(/\r?\n/).forEach((line) => {
    const index = line.indexOf("=");
    if (index > 0) rows[line.slice(0, index)] = line.slice(index + 1);
  });
  return rows;
}

async function loadDiagnostics() {
  try {
    const diagnostics = await window.ymhut.network.diagnostics();
    state.diagnostics = diagnostics;
    state.checks.host = true;
    setBadge("hostStatus", "ok", "本地");
  } catch (error) {
    state.checks.host = false;
    state.diagnostics = { interfaces: [], summary: {}, proxy: {}, note: error.message };
    setBadge("hostStatus", "bad", "失败");
  }
}

async function loadPublicIp() {
  try {
    const info = await firstSuccessful(endpoints.ipApis.map((item) => async () => {
      const { data } = await fetchJson(item.url);
      const normalized = normalizeIpInfo(item.name, data);
      if (!normalized?.ip) throw new Error(`${item.name} 未返回 IP`);
      return normalized;
    }));
    state.publicIp = info;
    state.checks.publicIp = true;
  } catch (error) {
    state.publicIp = { error: error.message };
    state.checks.publicIp = false;
  }
}

async function loadTrace() {
  try {
    const response = await bridgeFetch({ url: endpoints.trace });
    state.trace = parseTrace(response.content);
    state.checks.trace = true;
  } catch (error) {
    state.trace = { error: error.message };
    state.checks.trace = false;
  }
}

async function loadIpVersions() {
  const result = { ipv4: null, ipv6: null };
  try {
    const { data } = await fetchJson(endpoints.ipv4);
    result.ipv4 = data?.ip || null;
  } catch (error) {
    result.ipv4Error = error.message;
  }
  try {
    const { data } = await fetchJson(endpoints.ipv6);
    result.ipv6 = data?.ip || null;
  } catch (error) {
    result.ipv6Error = error.message;
  }
  state.ipVersions = result;
}

function renderIdentity() {
  const summary = state.diagnostics?.summary || {};
  const active = activeInterfaces();
  const localIpv4 = flatten(active.map((item) => item.ipv4));
  const localIpv6 = flatten(active.map((item) => item.ipv6));
  const publicIp = state.publicIp?.ip;

  $("primaryIp").textContent = publicIp || localIpv4[0] || localIpv6[0] || "网络未就绪";
  $("primarySummary").textContent = publicIp
    ? `${state.publicIp.isp || "未知 ISP"} · ${[state.publicIp.city, state.publicIp.region, state.publicIp.country].filter(Boolean).join(" / ") || "未知位置"} · ${state.publicIp.asn || "未知 ASN"}`
    : "未获得公网观测结果，已展示本机可见网络信息。";

  setFacts("ipDetails", [
    ["公网 IP", publicIp || "未获得"],
    ["ASN / ISP", [state.publicIp?.asn, state.publicIp?.isp].filter(Boolean).join(" / ")],
    ["国家地区", [state.publicIp?.city, state.publicIp?.region, state.publicIp?.country].filter(Boolean).join(" / ")],
    ["经纬度", state.publicIp?.latitude ? `${state.publicIp.latitude}, ${state.publicIp.longitude}` : ""],
    ["时区", state.publicIp?.timezone || state.diagnostics?.localTimeZone],
    ["活动接口", active.map((item) => item.name).join(" / ")],
    ["本机 IPv4", localIpv4.join(" / ")],
    ["本机 IPv6", localIpv6.join(" / ")],
    ["默认网关", (summary.defaultGateways || []).join(" / ")],
    ["DNS 服务器", (summary.dnsServers || []).join(" / ")],
    ["观测来源", state.publicIp?.source || state.publicIp?.error || "本地"]
  ]);
  setBadge("ipStatus", publicIp ? "ok" : "warn", publicIp ? "完成" : "降级");
}

function renderStack() {
  const active = activeInterfaces();
  const localIpv4 = flatten(active.map((item) => item.ipv4));
  const localIpv6 = flatten(active.map((item) => item.ipv6));
  const publicV4 = state.ipVersions?.ipv4;
  const publicV6 = state.ipVersions?.ipv6;
  setMetrics("stackDetails", [
    ["公网 IPv4", publicV4 || state.ipVersions?.ipv4Error || "未检测到", publicV4 ? "ok" : "warn"],
    ["公网 IPv6", publicV6 || state.ipVersions?.ipv6Error || "未检测到", publicV6 ? "ok" : "warn"],
    ["本机 IPv4", localIpv4.length ? `${localIpv4.length} 个地址` : "未发现", localIpv4.length ? "ok" : "bad"],
    ["本机 IPv6", localIpv6.length ? `${localIpv6.length} 个地址` : "未发现", localIpv6.length ? "ok" : "warn"],
    ["双栈状态", (publicV4 || localIpv4.length) && (publicV6 || localIpv6.length) ? "双栈可见" : "非完整双栈", (publicV4 || localIpv4.length) && (publicV6 || localIpv6.length) ? "ok" : "warn"]
  ]);
  setBadge("stackStatus", publicV4 || publicV6 || localIpv4.length || localIpv6.length ? "ok" : "bad", "完成");
}

function renderTrace() {
  const trace = state.trace || {};
  setFacts("traceDetails", [
    ["Colo", trace.colo || "--"],
    ["HTTP", trace.http || "--"],
    ["TLS", trace.tls || "--"],
    ["WARP", trace.warp || "--"],
    ["Gateway", trace.gateway || "--"],
    ["SNI", trace.sni || "--"],
    ["IP", trace.ip || "--"],
    ["错误", trace.error || ""]
  ]);
  setBadge("traceStatus", trace.colo ? "ok" : "warn", trace.colo ? "完成" : "降级");
}

function renderQuality() {
  const publicIp = state.publicIp || {};
  const proxy = state.diagnostics?.proxy || {};
  const trace = state.trace || {};
  const active = activeInterfaces();
  const localIps = flatten(active.map((item) => [...(item.ipv4 || []), ...(item.ipv6 || [])]));
  const hints = [];
  if (proxy.enabled) hints.push("系统代理已启用");
  if (trace.warp === "on" || trace.warp === "plus") hints.push("检测到 WARP");
  if (publicIp.error) hints.push("公网观测失败");
  if (localIps.some((ip) => ip.startsWith("10.") || ip.startsWith("192.168.") || ip.startsWith("172."))) hints.push("本机存在私网地址");
  const risk = publicIp.error ? "中" : proxy.enabled ? "需复核" : "低";
  setMetrics("qualityDetails", [
    ["质量评级", risk, risk === "低" ? "ok" : "warn"],
    ["代理/VPN 线索", hints.join(" / ") || "未发现明显线索", hints.length ? "warn" : "ok"],
    ["ASN 信息", publicIp.asn || "未知", publicIp.asn ? "ok" : "warn"],
    ["运营商", publicIp.isp || "未知", publicIp.isp ? "ok" : "warn"],
    ["观测一致性", state.ipVersions?.ipv4 && publicIp.ip && state.ipVersions.ipv4 !== publicIp.ip ? "IPv4 观测不一致" : "未发现冲突", "ok"]
  ]);
  setBadge("qualityStatus", risk === "低" ? "ok" : "warn", risk);
}

function renderBrowser() {
  const canvas = document.createElement("canvas");
  const gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
  const debug = gl?.getExtension("WEBGL_debug_renderer_info");
  state.browser = {
    language: navigator.language,
    languages: navigator.languages?.join(" / "),
    platform: navigator.platform,
    userAgent: navigator.userAgent,
    timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
    screen: `${screen.width}x${screen.height} / DPR ${window.devicePixelRatio}`,
    online: navigator.onLine ? "在线" : "离线",
    cookies: navigator.cookieEnabled ? "启用" : "禁用",
    hardwareConcurrency: navigator.hardwareConcurrency,
    memory: navigator.deviceMemory ? `${navigator.deviceMemory} GB` : "未暴露",
    touch: navigator.maxTouchPoints || 0,
    webglVendor: debug ? gl.getParameter(debug.UNMASKED_VENDOR_WEBGL) : "未暴露",
    webglRenderer: debug ? gl.getParameter(debug.UNMASKED_RENDERER_WEBGL) : "未暴露"
  };
  setFacts("browserDetails", [
    ["语言", state.browser.language],
    ["语言列表", state.browser.languages],
    ["平台", state.browser.platform],
    ["时区", state.browser.timezone],
    ["屏幕", state.browser.screen],
    ["在线状态", state.browser.online],
    ["Cookie", state.browser.cookies],
    ["CPU 线程", state.browser.hardwareConcurrency],
    ["内存", state.browser.memory],
    ["触控点", state.browser.touch],
    ["WebGL Vendor", state.browser.webglVendor],
    ["WebGL Renderer", state.browser.webglRenderer],
    ["UA", state.browser.userAgent]
  ]);
}

async function renderWebRtc() {
  if (!window.RTCPeerConnection) {
    $("webrtcDetails").textContent = "当前 WebView2 环境不支持 RTCPeerConnection。";
    setBadge("webrtcStatus", "warn", "不可用");
    return;
  }

  const candidates = new Set();
  try {
    const pc = new RTCPeerConnection({ iceServers: [{ urls: "stun:stun.l.google.com:19302" }] });
    pc.createDataChannel("probe");
    pc.onicecandidate = (event) => {
      if (event.candidate?.candidate) candidates.add(event.candidate.candidate);
    };
    await pc.setLocalDescription(await pc.createOffer());
    await new Promise((resolve) => setTimeout(resolve, 1800));
    pc.close();
    state.webrtc = Array.from(candidates);
    $("webrtcDetails").textContent = state.webrtc.length
      ? state.webrtc.join("\n")
      : "未暴露候选地址，或当前 WebView2 策略阻止采集。";
    const leaksPublic = state.webrtc.some((line) => /(srflx|relay)/i.test(line));
    setBadge("webrtcStatus", leaksPublic ? "warn" : "ok", leaksPublic ? "有候选" : "未发现");
  } catch (error) {
    $("webrtcDetails").textContent = `WebRTC 检测失败：${error.message}`;
    setBadge("webrtcStatus", "bad", "失败");
  }
}

async function renderDns() {
  const active = activeInterfaces();
  const rows = active.map((item) => [
    item.name,
    item.dnsServers?.length ? item.dnsServers.join(" / ") : "未配置",
    item.dnsServers?.length ? "ok" : "warn"
  ]);
  if (rows.length === 0) rows.push(["DNS", "未发现活动接口", "bad"]);

  try {
    const probeName = `ymhut-${Date.now()}.cloudflare.com`;
    const query = `${endpoints.doh}?name=${encodeURIComponent(probeName)}&type=A`;
    const response = await bridgeFetch({ url: query, headers: { accept: "application/dns-json" } });
    state.dnsProbe = parseJson(response.content) || {};
    rows.push(["DoH 探测", `${response.status} / ${Math.round(response.elapsedMs)} ms`, "ok"]);
    rows.push(["泄漏判断", "已列出本机 DNS；远端递归出口需专用回显域名才能精确归因", "warn"]);
  } catch (error) {
    rows.push(["DoH 探测", error.message, "warn"]);
  }

  setMetrics("dnsDetails", rows);
  setBadge("dnsStatus", rows.some((row) => row[2] === "ok") ? "ok" : "warn", "完成");
}

function renderLeakComparison() {
  const local = flatten(activeInterfaces().map((item) => [...(item.ipv4 || []), ...(item.ipv6 || [])]));
  const publicValues = [state.publicIp?.ip, state.ipVersions?.ipv4, state.ipVersions?.ipv6, state.trace?.ip].filter(Boolean);
  const webrtcValues = state.webrtc.join("\n");
  const leakedLocal = local.filter((ip) => webrtcValues.includes(ip));
  setMetrics("leakDetails", [
    ["公网观测", publicValues.join(" / ") || "未获得", publicValues.length ? "ok" : "warn"],
    ["WebRTC 本机地址", leakedLocal.join(" / ") || "未暴露完整本机地址", leakedLocal.length ? "warn" : "ok"],
    ["代理一致性", state.diagnostics?.proxy?.enabled ? "系统代理已启用，建议复核浏览器出口" : "未启用系统代理", state.diagnostics?.proxy?.enabled ? "warn" : "ok"],
    ["Trace 对照", state.trace?.ip && state.publicIp?.ip && state.trace.ip !== state.publicIp.ip ? "不同观测点结果不一致" : "未发现明显冲突", "ok"]
  ]);
  setBadge("leakStatus", leakedLocal.length ? "warn" : "ok", leakedLocal.length ? "需注意" : "正常");
}

async function renderLatency() {
  const targets = [
    ["Cloudflare", "1.1.1.1"],
    ["Google DNS", "8.8.8.8"],
    ["Quad9", "9.9.9.9"]
  ];
  const rows = [];
  for (const [name, host] of targets) {
    try {
      const result = await window.ymhut.network.ping({ host, count: 3, timeoutMs: 1800 });
      state.latency[name] = result;
      rows.push([name, result.avgMs >= 0 ? `${result.avgMs} ms / 丢包 ${result.lossPercent}%` : "无响应", result.avgMs >= 0 ? "ok" : "warn"]);
    } catch (error) {
      rows.push([name, error.message, "warn"]);
    }
  }
  rows.push(["DOM 响应", `${Math.round(performance.now() - state.startedAt)} ms`, "ok"]);
  setMetrics("latencyDetails", rows);
  setBadge("latencyStatus", rows.some((row) => row[2] === "ok") ? "ok" : "warn", "完成");
}

async function renderSpeed() {
  const active = activeInterfaces();
  const maxLink = Math.max(0, ...active.map((item) => Number(item.speedMbps || 0)));
  try {
    const downStart = performance.now();
    const down = await bridgeFetch({ url: endpoints.speedDown });
    const downSeconds = Math.max(0.001, (performance.now() - downStart) / 1000);
    const downMbps = (Number(down.content.length || 1000000) * 8 / downSeconds / 1000000);

    const upPayload = "0".repeat(250000);
    const upStart = performance.now();
    await bridgeFetch({ url: endpoints.speedUp, method: "POST", body: upPayload, headers: { "content-type": "text/plain" } });
    const upSeconds = Math.max(0.001, (performance.now() - upStart) / 1000);
    const upMbps = (upPayload.length * 8 / upSeconds / 1000000);

    state.speed = { downloadMbps: downMbps, uploadMbps: upMbps };
    $("speedValue").textContent = downMbps.toFixed(1);
    $("speedUnit").textContent = "Mbps down";
    $("speedNote").textContent = `上传 ${upMbps.toFixed(1)} Mbps；本机最大链路 ${maxLink ? `${maxLink.toLocaleString()} Mbps` : "未知"}。`;
    setBadge("speedStatus", "ok", "完成");
  } catch (error) {
    $("speedValue").textContent = maxLink ? maxLink.toLocaleString() : "--";
    $("speedUnit").textContent = "Mbps link";
    $("speedNote").textContent = maxLink
      ? `测速失败：${error.message}。当前显示本机网卡报告链路速率。`
      : `测速失败：${error.message}，且未发现可用链路速率。`;
    setBadge("speedStatus", maxLink ? "warn" : "bad", maxLink ? "链路" : "失败");
  }
}

function renderSecurity() {
  const rows = [
    ["HTTPS / TLS", state.trace?.tls ? `TLS ${state.trace.tls}` : "未获得 Trace", state.trace?.tls ? "ok" : "warn"],
    ["Cloudflare WARP", state.trace?.warp || "未知", state.trace?.warp === "off" ? "ok" : "warn"],
    ["系统代理", state.diagnostics?.proxy?.enabled ? `${state.diagnostics.proxy.mode} ${state.diagnostics.proxy.host || ""}` : "未启用", state.diagnostics?.proxy?.enabled ? "warn" : "ok"],
    ["WebRTC 泄漏", state.webrtc.length ? "存在候选地址，需检查是否暴露真实地址" : "未发现候选地址", state.webrtc.length ? "warn" : "ok"],
    ["DNS 配置", (state.diagnostics?.summary?.dnsServers || []).length ? "已发现 DNS 服务器" : "未发现 DNS", (state.diagnostics?.summary?.dnsServers || []).length ? "ok" : "warn"],
    ["浏览器指纹", "已采集 UA、语言、屏幕、WebGL、硬件线程等本地指标", "info"]
  ];
  setChecks("securityDetails", rows);
  setBadge("securityStatus", rows.some((row) => row[2] === "bad") ? "bad" : rows.some((row) => row[2] === "warn") ? "warn" : "ok", "完成");
}

function renderInterfaces() {
  const items = state.diagnostics?.interfaces || [];
  if (items.length === 0) {
    $("interfaceDetails").innerHTML = '<div class="metric"><span>接口</span><strong class="badText">未发现</strong></div>';
    return;
  }
  $("interfaceDetails").innerHTML = items.map((item) => `
    <div class="interfaceItem">
      <div>
        <strong>${escapeHtml(item.name)}</strong>
        <span>${escapeHtml(item.description)}</span>
      </div>
      <dl class="facts compact">
        <dt>状态</dt><dd>${escapeHtml(item.status)} · ${escapeHtml(item.type)}</dd>
        <dt>速率</dt><dd>${escapeHtml(item.speedMbps ? `${item.speedMbps} Mbps` : "--")}</dd>
        <dt>IPv4</dt><dd>${escapeHtml((item.ipv4 || []).join(" / ") || "--")}</dd>
        <dt>IPv6</dt><dd>${escapeHtml((item.ipv6 || []).join(" / ") || "--")}</dd>
        <dt>网关</dt><dd>${escapeHtml((item.gateways || []).join(" / ") || "--")}</dd>
        <dt>DNS</dt><dd>${escapeHtml((item.dnsServers || []).join(" / ") || "--")}</dd>
      </dl>
    </div>`).join("");
}

function renderStatusStrip() {
  const summary = state.diagnostics?.summary || {};
  const items = [
    ["公网 IP", state.publicIp?.ip || "未知"],
    ["IPv4 / IPv6", `${state.ipVersions?.ipv4 ? "4" : "-"} / ${state.ipVersions?.ipv6 ? "6" : "-"}`],
    ["活动接口", summary.activeInterfaceCount ?? 0],
    ["DNS", (summary.dnsServers || []).length]
  ];
  $("statusStrip").innerHTML = items.map(([label, value]) => `
    <div class="statusItem">
      <span>${escapeHtml(label)}</span>
      <strong>${escapeHtml(value)}</strong>
    </div>`).join("");
}

function buildReport() {
  const summary = state.diagnostics?.summary || {};
  return [
    "YMhut Box IPCheck 网络诊断报告",
    `生成时间：${new Date().toLocaleString()}`,
    `公网 IP：${state.publicIp?.ip || "--"}`,
    `ASN/ISP：${[state.publicIp?.asn, state.publicIp?.isp].filter(Boolean).join(" / ") || "--"}`,
    `位置：${[state.publicIp?.city, state.publicIp?.region, state.publicIp?.country].filter(Boolean).join(" / ") || "--"}`,
    `IPv4：${state.ipVersions?.ipv4 || "--"}`,
    `IPv6：${state.ipVersions?.ipv6 || "--"}`,
    `Cloudflare Trace：${state.trace?.colo || "--"} / WARP ${state.trace?.warp || "--"}`,
    `活动接口：${summary.activeInterfaceCount ?? 0}`,
    `DNS：${(summary.dnsServers || []).join(" / ") || "--"}`,
    `网关：${(summary.defaultGateways || []).join(" / ") || "--"}`,
    `WebRTC：${state.webrtc.join(" | ") || "未发现候选地址"}`,
    `测速：${state.speed ? `${state.speed.downloadMbps.toFixed(1)} down / ${state.speed.uploadMbps.toFixed(1)} up Mbps` : "--"}`,
    `浏览器：${state.browser.userAgent || "--"}`
  ].join("\n");
}

async function copyReport() {
  try {
    const report = buildReport();
    await window.ymhut.clipboard.writeText(report);
    await window.ymhut.output.set(report);
    setBadge("copyStatus", "ok", "已复制");
  } catch (error) {
    setBadge("copyStatus", "bad", "复制失败");
    await window.ymhut.log.warn("IPCheck copy failed", error.message);
  }
}

async function writeOutputDemo() {
  try {
    const report = buildReport();
    await window.ymhut.output.set(report);
    $("bridgeOutput").textContent = "已把当前诊断报告写入宿主输出区。";
    setBadge("bridgeStatus", "ok", "输出已写入");
  } catch (error) {
    $("bridgeOutput").textContent = `输出失败：${error.message}`;
    setBadge("bridgeStatus", "bad", "输出失败");
  }
}

async function saveSnapshotDemo() {
  try {
    const snapshot = {
      savedAt: new Date().toISOString(),
      ip: state.publicIp?.ip || "",
      ipv4: state.ipVersions?.ipv4 || "",
      ipv6: state.ipVersions?.ipv6 || "",
      colo: state.trace?.colo || ""
    };
    await window.ymhut.storage.set("lastSnapshot", JSON.stringify(snapshot));
    const stored = await window.ymhut.storage.get("lastSnapshot");
    $("bridgeOutput").textContent = `已保存插件私有状态：\n${stored}`;
    setBadge("bridgeStatus", "ok", "快照已保存");
  } catch (error) {
    $("bridgeOutput").textContent = `保存失败：${error.message}`;
    setBadge("bridgeStatus", "bad", "保存失败");
  }
}

async function openGuideDemo() {
  try {
    await window.ymhut.openExternal("https://github.com/YMhut/box-winUI3#plugins");
    $("bridgeOutput").textContent = "已请求使用安全浏览器打开插件规范链接。";
    setBadge("bridgeStatus", "ok", "链接已打开");
  } catch (error) {
    $("bridgeOutput").textContent = `打开链接失败：${error.message}`;
    setBadge("bridgeStatus", "bad", "链接失败");
  }
}

function cleanHost(value) {
  return String(value || "")
    .trim()
    .replace(/^https?:\/\//i, "")
    .split(/[/?#]/)[0];
}

function isIp(value) {
  return /^(\d{1,3}\.){3}\d{1,3}$/.test(value) || value.includes(":");
}

function ipToNumber(ip) {
  const parts = String(ip).split(".").map(Number);
  if (parts.length !== 4 || parts.some((part) => Number.isNaN(part) || part < 0 || part > 255)) return null;
  return (((parts[0] << 24) >>> 0) + (parts[1] << 16) + (parts[2] << 8) + parts[3]) >>> 0;
}

function domainMatches(target, domain) {
  const host = cleanHost(target).toLowerCase();
  const needle = String(domain || "").toLowerCase();
  return host === needle || host.endsWith(`.${needle}`);
}

function cidrMatches(ip, cidr) {
  const [base, bitsText] = String(cidr || "").split("/");
  const bits = Number(bitsText);
  const ipNumber = ipToNumber(ip);
  const baseNumber = ipToNumber(base);
  if (ipNumber === null || baseNumber === null || Number.isNaN(bits) || bits < 0 || bits > 32) return false;
  const mask = bits === 0 ? 0 : (0xffffffff << (32 - bits)) >>> 0;
  return (ipNumber & mask) === (baseNumber & mask);
}

async function runLookup() {
  const value = cleanHost($("lookupInput").value || $("primaryIp").textContent);
  if (!value) return;
  setBadge("toolStatus", "pending", "查询中");
  setOutput("lookupOutput", "正在查询 IP 信息...");
  try {
    const url = isIp(value) ? `https://ipapi.co/${encodeURIComponent(value)}/json/` : `https://ipapi.co/${encodeURIComponent(value)}/json/`;
    const { data } = await fetchJson(url);
    state.lookup = normalizeIpInfo("ipapi.co", data);
    setOutput("lookupOutput", shortJson(state.lookup || data));
    setBadge("toolStatus", "ok", "完成");
  } catch (error) {
    setOutput("lookupOutput", `查询失败：${error.message}`);
    setBadge("toolStatus", "bad", "失败");
  }
}

async function runDnsLookup() {
  const value = cleanHost($("dnsInput").value || "example.com");
  setOutput("dnsOutput", "正在解析...");
  try {
    const bridge = await window.ymhut.network.dnsLookup({ host: value });
    let doh = null;
    try {
      const { data } = await fetchJson(`${endpoints.doh}?name=${encodeURIComponent(value)}&type=A`, { headers: { accept: "application/dns-json" } });
      doh = data;
    } catch {
      doh = null;
    }
    setOutput("dnsOutput", shortJson({ systemResolver: bridge, cloudflareDoh: doh }));
  } catch (error) {
    setOutput("dnsOutput", `解析失败：${error.message}`);
  }
}

async function runPing() {
  const value = cleanHost($("pingInput").value || "1.1.1.1");
  setOutput("pingOutput", "正在 Ping...");
  try {
    const result = await window.ymhut.network.ping({ host: value, count: 5, timeoutMs: 2500 });
    setOutput("pingOutput", shortJson(result));
  } catch (error) {
    setOutput("pingOutput", `Ping 失败：${error.message}`);
  }
}

async function runTraceRoute() {
  const value = cleanHost($("traceInput").value || "1.1.1.1");
  setOutput("traceOutput", "正在追踪路由...");
  try {
    const result = await window.ymhut.network.traceRoute({ host: value, maxHops: 16, timeoutMs: 2200 });
    setOutput("traceOutput", shortJson(result));
  } catch (error) {
    setOutput("traceOutput", `追踪失败：${error.message}`);
  }
}

async function runWhois() {
  const value = cleanHost($("whoisInput").value || $("primaryIp").textContent);
  setOutput("whoisOutput", "正在查询 RDAP...");
  try {
    const url = `${isIp(value) ? endpoints.rdapIp : endpoints.rdapDomain}${encodeURIComponent(value)}`;
    const { data } = await fetchJson(url);
    setOutput("whoisOutput", shortJson(data));
  } catch (error) {
    setOutput("whoisOutput", `RDAP 查询失败：${error.message}`);
  }
}

async function runMacLookup() {
  const raw = $("macInput").value.trim();
  const oui = raw.replace(/[^0-9a-f]/gi, "").slice(0, 6).toUpperCase();
  if (oui.length < 6) {
    setOutput("macOutput", "请输入至少 6 位十六进制 OUI。");
    return;
  }
  if (macVendors[oui]) {
    setOutput("macOutput", `${raw}\nOUI: ${oui}\n厂商: ${macVendors[oui]}\n来源: 内置常用 OUI 表`);
    return;
  }
  setOutput("macOutput", "正在查询厂商...");
  try {
    const response = await bridgeFetch({ url: `${endpoints.mac}${encodeURIComponent(raw)}` });
    setOutput("macOutput", `${raw}\nOUI: ${oui}\n厂商: ${response.content.trim()}`);
  } catch (error) {
    setOutput("macOutput", `${raw}\nOUI: ${oui}\n未在内置表命中，在线查询失败：${error.message}`);
  }
}

async function runAsnConnectivity() {
  const value = cleanHost($("asnInput").value || state.publicIp?.ip || $("primaryIp").textContent);
  setOutput("asnOutput", "正在分析 ASN 连通性...");
  try {
    const ipValue = value.toUpperCase().startsWith("AS") ? state.publicIp?.ip : value;
    const rdap = ipValue ? (await fetchJson(`${endpoints.rdapIp}${encodeURIComponent(ipValue)}`)).data : null;
    const cidrs = (rdap?.cidr0_cidrs || []).map((item) => `${item.v4prefix || item.v6prefix}/${item.length}`);
    const pings = [];
    for (const target of ["1.1.1.1", "8.8.8.8", "9.9.9.9"]) {
      try {
        const ping = await window.ymhut.network.ping({ host: target, count: 2, timeoutMs: 1800 });
        pings.push({ target, avgMs: ping.avgMs, lossPercent: ping.lossPercent });
      } catch (error) {
        pings.push({ target, error: error.message });
      }
    }
    setOutput("asnOutput", shortJson({
      input: value,
      publicIp: state.publicIp?.ip,
      asn: state.publicIp?.asn,
      isp: state.publicIp?.isp,
      rdapName: rdap?.name,
      country: rdap?.country,
      cidrs,
      reachability: pings
    }));
  } catch (error) {
    setOutput("asnOutput", `ASN 分析失败：${error.message}`);
  }
}

async function runRuleTest() {
  const target = cleanHost($("ruleTargetInput").value || state.publicIp?.ip || "example.com");
  const ip = isIp(target) ? target : state.publicIp?.ip;
  const country = (state.publicIp?.countryCode || "").toUpperCase();
  const rules = ($("ruleInput").value || "DOMAIN-SUFFIX,example.com\nIP-CIDR,1.1.1.0/24\nGEOIP,CN")
    .split(/\r?\n/)
    .map((line) => line.trim())
    .filter(Boolean);
  const results = rules.map((line) => {
    const [typeRaw, valueRaw] = line.split(",").map((part) => part?.trim());
    const type = (typeRaw || "").toUpperCase();
    const value = valueRaw || "";
    let matched = false;
    if (type === "DOMAIN" || type === "DOMAIN-SUFFIX") matched = domainMatches(target, value);
    if (type === "IP-CIDR") matched = ip ? cidrMatches(ip, value) : false;
    if (type === "GEOIP") matched = country === value.toUpperCase();
    if (type === "KEYWORD") matched = target.toLowerCase().includes(value.toLowerCase());
    return { rule: line, matched };
  });
  setOutput("ruleOutput", shortJson({ target, ip, country, results, firstMatch: results.find((item) => item.matched) || null }));
}

async function runCensorshipCheck() {
  const custom = $("censorInput").value.trim();
  const targets = custom ? [custom] : [
    "https://www.cloudflare.com/cdn-cgi/trace",
    "https://www.google.com/generate_204",
    "https://www.wikipedia.org/",
    "https://www.github.com/"
  ];
  setOutput("censorOutput", "正在检查可达性...");
  const rows = [];
  for (const target of targets) {
    const url = /^https?:\/\//i.test(target) ? target : `https://${target}`;
    try {
      const started = performance.now();
      const response = await window.ymhut.http.fetch({ url });
      rows.push({ url, ok: response.ok, status: response.status, elapsedMs: Math.round(performance.now() - started) });
    } catch (error) {
      rows.push({ url, ok: false, error: error.message });
    }
  }
  setOutput("censorOutput", shortJson(rows));
}

async function runInvisibilityTest() {
  const expected = $("invisibleInput").value.trim().toUpperCase();
  const local = activeInterfaces();
  const dns = flatten(local.map((item) => item.dnsServers));
  const localIps = flatten(local.map((item) => [...(item.ipv4 || []), ...(item.ipv6 || [])]));
  const publicIp = state.publicIp?.ip;
  const country = (state.publicIp?.countryCode || "").toUpperCase();
  const findings = [
    { item: "公网 IP", value: publicIp || "未知", status: publicIp ? "ok" : "warn" },
    { item: "期望国家", value: expected || "未指定", status: expected && country && expected !== country ? "warn" : "ok" },
    { item: "WebRTC 候选", value: state.webrtc.length ? `${state.webrtc.length} 条` : "未发现", status: state.webrtc.length ? "warn" : "ok" },
    { item: "本机私网地址", value: localIps.filter((ip) => ip.startsWith("10.") || ip.startsWith("192.168.") || ip.startsWith("172.")).join(" / ") || "未发现", status: "ok" },
    { item: "DNS 服务器", value: dns.join(" / ") || "未知", status: dns.length ? "ok" : "warn" },
    { item: "系统代理", value: state.diagnostics?.proxy?.enabled ? state.diagnostics.proxy.mode : "未启用", status: state.diagnostics?.proxy?.enabled ? "warn" : "ok" },
    { item: "Trace WARP", value: state.trace?.warp || "未知", status: state.trace?.warp === "off" ? "ok" : "warn" }
  ];
  setOutput("invisibleOutput", shortJson({
    score: findings.filter((item) => item.status === "warn").length === 0 ? "隐私暴露线索较少" : "存在需要复核的暴露线索",
    country,
    expectedCountry: expected || null,
    findings
  }));
}

async function runAll() {
  state.startedAt = performance.now();
  ["ipStatus", "stackStatus", "traceStatus", "hostStatus", "webrtcStatus", "dnsStatus", "latencyStatus", "speedStatus", "qualityStatus", "securityStatus", "leakStatus"].forEach((id) => setBadge(id, "pending", "检测中"));
  $("primaryIp").textContent = "正在检测...";
  $("primarySummary").textContent = "正在并行检测公网视角、本机网络、DNS、WebRTC、浏览器指纹和链路质量。";
  await loadDiagnostics();
  await Promise.allSettled([loadPublicIp(), loadTrace(), loadIpVersions()]);
  renderBrowser();
  renderIdentity();
  renderStack();
  renderTrace();
  renderQuality();
  await renderWebRtc();
  await renderDns();
  renderLeakComparison();
  await renderLatency();
  await renderSpeed();
  renderSecurity();
  renderInterfaces();
  renderStatusStrip();
  await window.ymhut.log.info("IPCheck diagnostics completed", JSON.stringify({
    publicIp: state.publicIp?.ip,
    ipv4: state.ipVersions?.ipv4,
    ipv6: state.ipVersions?.ipv6,
    colo: state.trace?.colo
  }));
}

function wireAdvancedTools() {
  $("lookupBtn").addEventListener("click", runLookup);
  $("dnsBtn").addEventListener("click", runDnsLookup);
  $("pingBtn").addEventListener("click", runPing);
  $("traceBtn").addEventListener("click", runTraceRoute);
  $("whoisBtn").addEventListener("click", runWhois);
  $("macBtn").addEventListener("click", runMacLookup);
  $("asnBtn").addEventListener("click", runAsnConnectivity);
  $("ruleBtn").addEventListener("click", runRuleTest);
  $("censorBtn").addEventListener("click", runCensorshipCheck);
  $("invisibleBtn").addEventListener("click", runInvisibilityTest);
  ["lookupInput", "dnsInput", "pingInput", "traceInput", "whoisInput", "macInput", "asnInput", "ruleTargetInput", "censorInput", "invisibleInput"].forEach((id) => {
    $(id).addEventListener("keydown", (event) => {
      if (event.key !== "Enter") return;
      event.preventDefault();
      const buttonId = {
        ruleTargetInput: "ruleBtn",
        censorInput: "censorBtn",
        invisibleInput: "invisibleBtn"
      }[id] || id.replace("Input", "Btn");
      $(buttonId)?.click();
    });
  });
}

document.addEventListener("DOMContentLoaded", () => {
  $("rerunBtn").addEventListener("click", runAll);
  $("copyBtn").addEventListener("click", copyReport);
  $("outputDemoBtn").addEventListener("click", writeOutputDemo);
  $("storageDemoBtn").addEventListener("click", saveSnapshotDemo);
  $("guideDemoBtn").addEventListener("click", openGuideDemo);
  wireAdvancedTools();
  runAll();
});
