async function openEntityDetail(item) {
  state.entityDetailItem = item;
  state.entityDetailPayload = null;
  state.entityDetailIntraday = null;
  state.entityDetailChartMode = "daily";
  const requestSequence = ++state.entityDetailRequestSequence;
  syncDetailChartButtons("entity", "daily");
  setText("entityDetailCode", item.code || item.id || "--");
  setText("entityDetailName", item.name || "--");
  setText("entityDetailValue", "--");
  setText("entityDetailChange", "--");
  setText("entityDetailType", item.type_label || "--");
  setText("entityDetailDate", "正在加载行情");
  document.querySelector("#entityDetailChange").className = "";
  renderEmptyState("entityDetailMetrics", "正在加载交易数据");
  openModalDialog(elements.entityDetailDialog);
  clearEntityDetailChart("正在加载日 K 数据");
  try {
    const params = new URLSearchParams({ type: item.type, id: item.id, trade_date: elements.tradeDate.value });
    const payload = await apiRequest(`/api/search/detail?${params}`);
    if (requestSequence !== state.entityDetailRequestSequence) return;
    state.entityDetailPayload = payload;
    const entity = payload.entity || {};
    setText("entityDetailCode", entity.code || item.code || "--");
    setText("entityDetailName", entity.name || item.name || "--");
    setText("entityDetailValue", meaningfulNumber(entity.value) && number(entity.value) !== 0 ? formatNumber(entity.value, 2) : "--");
    setText("entityDetailChange", `${signed(entity.change)}%`);
    setText("entityDetailType", entity.type_label || item.type_label || "--");
    document.querySelector("#entityDetailChange").className = changeClass(entity.change);
    renderEntityDetailMetrics(payload.metrics || []);
    if (state.entityDetailChartMode === "daily") {
      setText("entityDetailDate", `${payload.meta?.realtime ? "实时" : "收盘"} · ${payload.meta?.trade_date || "--"}`);
      requestAnimationFrame(() => drawEntityDetailChart(payload.series || []));
    }
  } catch (error) {
    if (requestSequence !== state.entityDetailRequestSequence) return;
    setText("entityDetailDate", "行情加载失败");
    renderEmptyState("entityDetailMetrics", error.message || "交易数据加载失败");
    if (state.entityDetailChartMode === "daily") clearEntityDetailChart(error.message || "行情加载失败");
    showToast(error.message || "详情加载失败");
  }
}
async function selectEntityDetailChart(mode) {
  const selected = mode === "intraday" ? "intraday" : "daily";
  state.entityDetailChartMode = selected;
  syncDetailChartButtons("entity", selected);
  if (selected === "daily") {
    const payload = state.entityDetailPayload;
    if (payload) {
      setText("entityDetailDate", `${payload.meta?.realtime ? "实时" : "收盘"} · ${payload.meta?.trade_date || "--"}`);
      requestAnimationFrame(() => drawEntityDetailChart(payload.series || []));
    } else clearEntityDetailChart("正在加载日 K 数据");
    return;
  }

  if (state.entityDetailIntraday) {
    renderEntityIntraday(state.entityDetailIntraday);
    return;
  }
  const item = state.entityDetailItem;
  if (!item) return;
  const requestSequence = state.entityDetailRequestSequence;
  setText("entityDetailDate", "正在加载分时");
  clearEntityDetailChart("正在加载分时数据");
  try {
    const params = new URLSearchParams({ type: item.type, id: item.id });
    const payload = await apiRequest(`/api/chart/intraday?${params}`);
    if (requestSequence !== state.entityDetailRequestSequence) return;
    state.entityDetailIntraday = payload;
    if (state.entityDetailChartMode === "intraday") renderEntityIntraday(payload);
  } catch (error) {
    if (requestSequence !== state.entityDetailRequestSequence || state.entityDetailChartMode !== "intraday") return;
    setText("entityDetailDate", "分时暂不可用");
    clearEntityDetailChart(error.message || "分时行情暂不可用");
  }
}

function renderEntityIntraday(payload) {
  const points = payload.points || [];
  if (!points.length) {
    setText("entityDetailDate", "分时暂不可用");
    clearEntityDetailChart("分时行情暂不可用");
    return;
  }
  setText("entityDetailDate", `分时 · ${payload.meta?.trade_date || "--"}`);
  requestAnimationFrame(() => {
    if (state.entityDetailChartMode !== "intraday") return;
    drawIntradayCanvas(elements.entityDetailChart, points, [], payload.meta?.previous_close);
  });
}

function syncDetailChartButtons(scope, mode) {
  const selector = scope === "stock" ? "[data-stock-detail-chart]" : "[data-entity-detail-chart]";
  const datasetKey = scope === "stock" ? "stockDetailChart" : "entityDetailChart";
  document.querySelectorAll(selector).forEach((button) => {
    const active = button.dataset[datasetKey] === mode;
    button.classList.toggle("active", active);
    button.setAttribute("aria-pressed", String(active));
  });
}

function renderEntityDetailMetrics(metrics) {
  const container = document.querySelector("#entityDetailMetrics");
  if (!metrics.length) {
    renderEmptyState(container, "暂无交易数据");
    return;
  }
  container.innerHTML = metrics.map((metric) => {
    const value = typeof metric.value === "number" ? formatNumber(metric.value, Number.isInteger(metric.value) ? 0 : 2) : String(metric.value ?? "--");
    const tone = metric.tone === "change" ? changeClass(metric.value) : "";
    return `<div><dt>${escapeHtml(metric.label)}</dt><dd class="${tone}">${escapeHtml(value)}${escapeHtml(metric.unit || "")}</dd></div>`;
  }).join("");
}

function drawEntityDetailChart(series, canvas = elements.entityDetailChart) {
  const candles = (series || []).filter((item) => number(item.close) > 0).map((item) => {
    const close = number(item.close);
    const open = number(item.open) || close;
    const high = Math.max(number(item.high) || close, open, close);
    const low = Math.min(number(item.low) || close, open, close);
    return { ...item, open, high, low, close };
  });
  if (!candles.length) {
    clearEntityDetailChart("暂无日 K 数据", canvas);
    return;
  }
  const rect = canvas.getBoundingClientRect();
  const ratio = window.devicePixelRatio || 1;
  const width = Math.max(320, rect.width);
  const height = Math.max(220, rect.height);
  canvas.width = Math.round(width * ratio);
  canvas.height = Math.round(height * ratio);
  const context = canvas.getContext("2d");
  const palette = currentChartPalette();
  context.setTransform(ratio, 0, 0, ratio, 0, 0);
  context.clearRect(0, 0, width, height);
  context.fillStyle = palette.background;
  context.fillRect(0, 0, width, height);
  const left = 48;
  const right = 12;
  const top = 14;
  const bottom = 22;
  const volumeHeight = 54;
  const gap = 12;
  const priceBottom = height - bottom - volumeHeight - gap;
  const plotWidth = width - left - right;
  const maximum = Math.max(...candles.map((item) => item.high));
  const minimum = Math.min(...candles.map((item) => item.low));
  const range = Math.max(maximum - minimum, maximum * 0.01, 0.01);
  const maxVolume = Math.max(...candles.map((item) => number(item.volume)), 1);
  const priceY = (value) => top + (maximum - value) / range * (priceBottom - top);
  const step = plotWidth / candles.length;
  const candleWidth = clamp(step * 0.62, 2, 8);
  context.strokeStyle = palette.grid;
  context.fillStyle = palette.axis;
  context.font = "11px Microsoft YaHei";
  context.textAlign = "right";
  for (let line = 0; line <= 4; line += 1) {
    const lineY = top + (priceBottom - top) * line / 4;
    context.beginPath();
    context.moveTo(left, lineY);
    context.lineTo(width - right, lineY);
    context.stroke();
    context.fillText((maximum - range * line / 4).toFixed(2), left - 6, lineY + 4);
  }

  candles.forEach((item, index) => {
    const x = left + step * index + step / 2;
    const color = drawCandlestick(context, x, item, priceY, candleWidth, palette);
    const volumeBarHeight = number(item.volume) / maxVolume * volumeHeight;
    context.fillStyle = color;
    context.globalAlpha = 0.72;
    context.fillRect(x - candleWidth / 2, height - bottom - volumeBarHeight, candleWidth, volumeBarHeight);
    context.globalAlpha = 1;
  });

  context.textAlign = "center";
  context.fillStyle = palette.axis;
  [0, Math.floor((candles.length - 1) / 2), candles.length - 1].forEach((index) => {
    const x = left + step * index + step / 2;
    context.fillText(String(candles[index].trade_date || "").slice(5), x, height - 5);
  });
}

function clearEntityDetailChart(message, canvas = elements.entityDetailChart) {
  const rect = canvas.getBoundingClientRect();
  const width = Math.max(320, Math.round(rect.width || 680));
  const height = Math.max(220, Math.round(rect.height || 300));
  canvas.width = width;
  canvas.height = height;
  const context = canvas.getContext("2d");
  const palette = currentChartPalette();
  context.fillStyle = palette.background;
  context.fillRect(0, 0, width, height);
  context.fillStyle = palette.axis;
  context.font = "13px Microsoft YaHei";
  context.textAlign = "center";
  context.fillText(message, width / 2, height / 2);
}
