"use client";

import { FormEvent, useEffect, useMemo, useState } from "react";
import {
  CATALOG_COUNTS,
  CATALOG_PRODUCTS as RAW_CATALOG_PRODUCTS,
  type CatalogProduct,
} from "./catalog-data";
import { STEERING_WHEEL_ACCESSORIES } from "./catalog-accessories";
import { PRECISION_GEAR_PRODUCTS, PRECISION_GEAR_SUBCATEGORIES } from "./precision-gear-data";
import { getCatalogProductDimensionImage, getCatalogProductImage } from "./catalog-image-map";

const CATALOG_PRODUCTS = [...RAW_CATALOG_PRODUCTS, ...STEERING_WHEEL_ACCESSORIES].map((product) => ({
  ...product,
  image: getCatalogProductImage(product),
}));

type Requirements = {
  application: string;
  category: string;
  torque: number;
  voltage: number;
  weightLimit: number;
  angle: string;
  control: string;
  gear: string;
  annualVolume: string;
  firstOrderQuantity: string;
  currentModel: string;
  otherRequirements: string;
  painPoint: string;
};

type CatalogVisualMode = "main" | "size";

const APPLICATIONS = [
  { name: "AI毛绒", note: "头部、耳朵、手臂等轻量动作" },
  { name: "智能玩具", note: "互动机构、表情和行走结构" },
  { name: "教育/积木", note: "STEAM套件与积木动力模块" },
  { name: "微型机器人", note: "关节、夹爪和小型机械臂" },
  { name: "云台/航模", note: "飞行控制、云台与模型机构" },
  { name: "工业设备", note: "控制机构与定制传动组件" },
];

const PRIMARY_CATALOG_CATEGORIES = [
  "标准舵机",
  "异形舵机",
  "全金属舵机",
  "大扭矩舵机",
  "积木舵机",
  "标准齿轮箱",
  "翻盖电机",
  "舵盘配件",
];

const CATALOG_FILTER_CATEGORIES = ["全部产品", ...PRIMARY_CATALOG_CATEGORIES, "静音舵机"];

const FEATURED_SPEC_ORDER = [
  "堵转扭矩",
  "额定电压",
  "电压范围",
  "信号类型",
  "通讯方式",
  "齿轮比",
  "寿命",
  "花键大小",
  "类别",
  "材质",
  "重量",
  "产品尺寸",
  "外形尺寸",
];

function getFeaturedSpecs(product: CatalogProduct) {
  return FEATURED_SPEC_ORDER
    .filter((label) => product.specs[label])
    .slice(0, 3)
    .map((label) => [label, product.specs[label]] as const);
}

const PRECISION_GEAR_CARD_SPEC_ORDER = [
  "模数",
  "齿数",
  "材质",
  "外径（mm）",
  "长（mm）",
  "宽（mm）",
  "高（mm）",
  "孔径",
  "类别",
];

function getPrecisionGearCardSpecs(product: CatalogProduct) {
  return PRECISION_GEAR_CARD_SPEC_ORDER
    .filter((label) => product.specs[label])
    .slice(0, 2)
    .map((label) => [label, product.specs[label]] as const);
}

const SERVO_CATEGORIES = ["标准舵机", "异形舵机", "全金属舵机", "大扭矩舵机", "积木舵机"];
const SILENT_SERVO_CATEGORY = "静音舵机";
const CUSTOM_SERVO_CATEGORY = "非标准舵机定制";
const TORQUE_MIN = 0.09;
const TORQUE_MAX = 920;
const TORQUE_PRESETS = [0.1, 1, 5, 20, 100, 300, 920];

const APPLICATION_CATEGORY_MAP: Record<string, string[]> = {
  AI毛绒: ["标准舵机", "异形舵机"],
  智能玩具: ["标准舵机", "异形舵机", "积木舵机"],
  "教育/积木": ["积木舵机", "标准舵机"],
  微型机器人: ["标准舵机", "异形舵机", "全金属舵机"],
  "云台/航模": ["标准舵机", "全金属舵机"],
  工业设备: ["全金属舵机", "大扭矩舵机", "异形舵机"],
};

function parseNumbers(value = "") {
  return (value.match(/\d+(?:\.\d+)?/g) ?? []).map(Number);
}

function isSilentServo(product: CatalogProduct) {
  return SERVO_CATEGORIES.includes(product.category) &&
    [product.name, ...Object.values(product.specs)].join(" ").includes("静音");
}

const SILENT_SERVO_COUNT = CATALOG_PRODUCTS.filter(isSilentServo).length;

function getCategoryCount(category: string) {
  return category === SILENT_SERVO_CATEGORY
    ? SILENT_SERVO_COUNT
    : category === "舵盘配件"
      ? STEERING_WHEEL_ACCESSORIES.length
      : CATALOG_COUNTS[category];
}

type ProductScale = {
  key: string;
  label: string;
  unit: "g" | "kg";
  value: number;
};

function getProductScale(product: CatalogProduct): ProductScale | null {
  const kilogramMatch = product.name.match(/(\d+(?:\.\d+)?)\s*(?:kg|千克)/i);
  if (kilogramMatch) {
    const value = Number(kilogramMatch[1]);
    return { key: `kg:${value}`, label: `${value}kg`, unit: "kg", value };
  }

  const gramMatch = product.name.match(/(\d+(?:\.\d+)?)\s*(?:g|克)/i);
  if (gramMatch) {
    const value = Number(gramMatch[1]);
    return { key: `g:${value}`, label: `${value}g`, unit: "g", value };
  }

  return null;
}

const PRODUCT_SCALE_OPTIONS = [...CATALOG_PRODUCTS.reduce((options, product) => {
  const scale = getProductScale(product);
  if (!scale) return options;
  const current = options.get(scale.key);
  options.set(scale.key, { ...scale, count: (current?.count ?? 0) + 1 });
  return options;
}, new Map<string, ProductScale & { count: number }>()).values()].sort(
  (a, b) => (a.unit === b.unit ? a.value - b.value : a.unit === "g" ? -1 : 1),
);

const GRAM_SCALE_OPTIONS = PRODUCT_SCALE_OPTIONS.filter((option) => option.unit === "g");
const KILOGRAM_SCALE_OPTIONS = PRODUCT_SCALE_OPTIONS.filter((option) => option.unit === "kg");
const UNMARKED_SCALE_COUNT = CATALOG_PRODUCTS.length - PRODUCT_SCALE_OPTIONS.reduce(
  (total, option) => total + option.count,
  0,
);

function inferWeight(product: CatalogProduct) {
  const listedWeight = parseNumbers(product.specs["重量"])[0];
  if (Number.isFinite(listedWeight)) return listedWeight;
  if (product.category !== "标准舵机") return null;
  const namedWeight = product.name.match(/(\d+(?:\.\d+)?)\s*(?:g|克)/i);
  return namedWeight ? Number(namedWeight[1]) : null;
}

function classifyGear(value = "") {
  const hasPlastic = /塑胶|塑料/.test(value);
  const hasMetal = /金属|铜|粉末冶金|滚齿/.test(value);
  if (hasPlastic && hasMetal) return "混合齿";
  if (hasMetal) return "全金属齿";
  if (hasPlastic) return "塑胶齿";
  return "未标注";
}

function controlMatches(control: string, productControl: string) {
  if (control === "不限") return true;
  const value = productControl.toUpperCase();
  if (control === "PWM/三线") return value.includes("PWM") || /3线|3PIN/.test(value);
  if (control === "串口/TTL") return value.includes("TTL") || value.includes("串口");
  if (control === "二/四/五线") return /[245]线|[245]PIN/.test(value);
  return value.includes(control.toUpperCase());
}

function angleMatches(angle: string, productAngle: string) {
  if (angle === "不限") return true;
  if (!productAngle) return false;
  const firstAngle = parseNumbers(productAngle)[0] ?? 0;
  if (angle === "135°") return firstAngle > 0 && firstAngle <= 135;
  if (angle === "180°") return firstAngle > 135 && firstAngle <= 180;
  if (angle === "270–330°") return firstAngle >= 270 && firstAngle < 360;
  return productAngle.includes("多圈") || firstAngle >= 360;
}

function formatTorque(value: number) {
  if (value < 1) return value.toFixed(2).replace(/0+$/, "").replace(/\.$/, "");
  if (value < 100) return value.toFixed(1).replace(/\.0$/, "");
  return Math.round(value).toString();
}

function torqueToSlider(value: number) {
  return ((Math.log(value) - Math.log(TORQUE_MIN)) / (Math.log(TORQUE_MAX) - Math.log(TORQUE_MIN))) * 100;
}

function sliderToTorque(position: number) {
  const value = Math.exp(
    Math.log(TORQUE_MIN) + (position / 100) * (Math.log(TORQUE_MAX) - Math.log(TORQUE_MIN)),
  );
  if (value < 1) return Number(value.toFixed(2));
  if (value < 100) return Number(value.toFixed(1));
  return Math.round(value);
}

const SELECTOR_PRODUCTS = CATALOG_PRODUCTS.filter((product) =>
  SERVO_CATEGORIES.includes(product.category),
).map((product) => {
  const voltageValues = parseNumbers(product.specs["电压范围"]);
  const ratedVoltage = product.ratedVoltage ?? 0;
  const control = [
    product.specs["信号类型"],
    product.specs["通讯方式"],
    product.specs["端子连接线"],
    product.specs["连接线类型"],
  ].filter(Boolean).join(" · ");
  return {
    ...product,
    torque: product.torqueValue ?? 0,
    voltageMin: voltageValues[0] ?? ratedVoltage,
    voltageMax: voltageValues.at(-1) ?? ratedVoltage,
    weight: inferWeight(product),
    isSilent: isSilentServo(product),
    gear: classifyGear(product.specs["齿轮材质"]),
    angle: product.specs["可操作角度"] ?? product.specs["操作角度范围"] ?? "",
    control,
    speed: product.specs["空载速度"] ?? product.specs["转动速度"] ?? "",
    size: product.specs["产品尺寸"] ?? product.specs["外形尺寸"] ?? "",
  };
});

const RATED_VOLTAGES = [...new Set(
  SELECTOR_PRODUCTS
    .map((product) => product.ratedVoltage)
    .filter((voltage): voltage is number => voltage !== null),
)].sort((a, b) => a - b);

const DEFAULT_REQUIREMENTS: Requirements = {
  application: "",
  category: "全部舵机",
  torque: 2,
  voltage: 5,
  weightLimit: 0,
  angle: "不限",
  control: "不限",
  gear: "不限",
  annualVolume: "5000–50000件",
  firstOrderQuantity: "",
  currentModel: "",
  otherRequirements: "",
  painPoint: "交期",
};

function getMatches(requirements: Requirements) {
  return SELECTOR_PRODUCTS.map((product) => {
    let score = 20;
    const reasons: string[] = [];
    const categoryOk = requirements.category === "全部舵机" ||
      requirements.category === product.category ||
      (requirements.category === SILENT_SERVO_CATEGORY && product.isSilent);
    const torqueOk = product.torque >= requirements.torque;
    const voltageOk = requirements.voltage === product.ratedVoltage;
    const weightOk =
      requirements.weightLimit === 0 || product.weight === null || product.weight <= requirements.weightLimit;
    const gearOk = requirements.gear === "不限" || requirements.gear === product.gear;
    const angleOk = angleMatches(requirements.angle, product.angle);
    const controlOk = controlMatches(requirements.control, product.control);
    const coreCompatible = categoryOk && torqueOk && voltageOk && weightOk && gearOk && angleOk && controlOk;

    if (categoryOk) score += requirements.category === "全部舵机" ? 6 : 16;
    else score -= 120;

    if (APPLICATION_CATEGORY_MAP[requirements.application]?.includes(product.category)) {
      score += 12;
      reasons.push(`适合${requirements.application}场景`);
    }

    if (torqueOk) {
      const ratio = product.torque / requirements.torque;
      score += Math.max(5, 28 - Math.log10(Math.max(1, ratio)) * 9);
      const margin = Math.round((product.torque / requirements.torque - 1) * 100);
      reasons.push(`扭矩满足，约有${Math.max(0, margin)}%余量`);
    } else {
      score -= 120;
    }

    if (voltageOk) {
      score += 22;
      reasons.push(`${requirements.voltage}V额定电压匹配`);
    } else {
      score -= 90;
    }

    if (requirements.weightLimit > 0) {
      if (product.weight === null) score -= 6;
      else if (weightOk) {
        score += 10;
        reasons.push(`重量${product.weight}g，符合上限`);
      } else score -= 45;
    }

    if (requirements.gear !== "不限") score += gearOk ? 10 : -40;
    if (requirements.angle !== "不限") score += angleOk ? 10 : -40;
    if (requirements.control !== "不限") score += controlOk ? 12 : -50;

    if (requirements.painPoint === "成本" && product.gear === "塑料齿") score += 8;
    if (requirements.painPoint === "耐久" && product.gear === "全金属齿") score += 8;
    if (requirements.painPoint === "体积" && product.weight !== null && product.weight <= 9) score += 8;

    return {
      product,
      score,
      coreCompatible,
      confidence: Math.max(48, Math.min(97, Math.round(score))),
      reasons: reasons.slice(0, 3),
    };
  }).sort((a, b) => Number(b.coreCompatible) - Number(a.coreCompatible) || b.score - a.score);
}

function Metric({ label, value }: { label: string; value: string }) {
  return (
    <div className="metric">
      <span>{label}</span>
      <strong>{value}</strong>
    </div>
  );
}

type SaveProductRequest = {
  product: CatalogProduct;
  badge?: string;
  subtitle?: string;
  extraSpecs?: Array<[string, string]>;
};

function getSaveProductSpecs(product: CatalogProduct, extraSpecs: Array<[string, string]> = []) {
  return [
    ...extraSpecs.filter(([, value]) => value),
    ...Object.entries(product.specs).filter(([, value]) => value),
  ];
}

function wrapCanvasText(context: CanvasRenderingContext2D, value: string, maxWidth: number, maxLines = 2) {
  const characters = Array.from(String(value));
  const lines: string[] = [];
  let current = "";

  for (const character of characters) {
    const next = current + character;
    if (current && context.measureText(next).width > maxWidth) {
      lines.push(current);
      current = character;
      if (lines.length === maxLines) break;
    } else {
      current = next;
    }
  }

  if (lines.length < maxLines && current) lines.push(current);
  if (lines.length === maxLines && characters.join("").length > lines.join("").length) {
    const last = lines[maxLines - 1] ?? "";
    lines[maxLines - 1] = `${last.slice(0, Math.max(1, last.length - 1))}…`;
  }
  return lines;
}

function drawRoundedRect(
  context: CanvasRenderingContext2D,
  x: number,
  y: number,
  width: number,
  height: number,
  radius: number,
  fill: string,
  stroke?: string,
) {
  context.beginPath();
  context.moveTo(x + radius, y);
  context.lineTo(x + width - radius, y);
  context.quadraticCurveTo(x + width, y, x + width, y + radius);
  context.lineTo(x + width, y + height - radius);
  context.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
  context.lineTo(x + radius, y + height);
  context.quadraticCurveTo(x, y + height, x, y + height - radius);
  context.lineTo(x, y + radius);
  context.quadraticCurveTo(x, y, x + radius, y);
  context.closePath();
  context.fillStyle = fill;
  context.fill();
  if (stroke) {
    context.strokeStyle = stroke;
    context.lineWidth = 2;
    context.stroke();
  }
}

function loadProductCanvasImage(src: string) {
  return new Promise<HTMLImageElement>((resolve, reject) => {
    const image = new Image();
    image.onload = () => resolve(image);
    image.onerror = () => reject(new Error(`产品图片加载失败：${src}`));
    image.src = src;
  });
}

async function renderProductCardPng({ product, badge, subtitle, extraSpecs = [] }: SaveProductRequest) {
  const specs = getSaveProductSpecs(product, extraSpecs);
  const columnCount = 2;
  const rowCount = Math.max(1, Math.ceil(specs.length / columnCount));
  const cardWidth = 1200;
  const padding = 52;
  const headerHeight = 152;
  const specCellHeight = 70;
  const specGap = 10;
  const mainHeight = Math.max(390, rowCount * specCellHeight + (rowCount - 1) * specGap + 28);
  const cardHeight = padding + headerHeight + 24 + mainHeight + 24 + 42 + padding;
  const canvas = document.createElement("canvas");
  canvas.width = cardWidth;
  canvas.height = cardHeight;
  const context = canvas.getContext("2d");
  if (!context) throw new Error("当前浏览器不支持图片生成");

  context.fillStyle = "#eef3fa";
  context.fillRect(0, 0, cardWidth, cardHeight);
  drawRoundedRect(context, 18, 18, cardWidth - 36, cardHeight - 36, 26, "#ffffff", "#d9e3f2");
  context.fillStyle = "#185ee8";
  context.fillRect(padding, padding, 110, 7);

  context.fillStyle = "#123267";
  context.font = "800 25px -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', sans-serif";
  context.fillText("GAUDELOT", padding, padding + 34);
  context.fillStyle = "#7b8ca8";
  context.font = "600 15px -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', sans-serif";
  context.fillText("高徳乐产品资料", padding + 145, padding + 33);

  if (badge) {
    const badgeWidth = Math.max(100, context.measureText(badge).width + 34);
    drawRoundedRect(context, cardWidth - padding - badgeWidth, padding + 8, badgeWidth, 32, 16, "#edf4ff");
    context.fillStyle = "#185ee8";
    context.font = "700 14px -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', sans-serif";
    context.fillText(badge, cardWidth - padding - badgeWidth + 17, padding + 29);
  }

  context.fillStyle = "#111d34";
  context.font = "800 30px -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', sans-serif";
  const titleLines = wrapCanvasText(context, product.name, 760, 2);
  titleLines.forEach((line, index) => context.fillText(line, padding, padding + 82 + index * 36));
  context.fillStyle = "#71809a";
  context.font = "600 17px ui-monospace, SFMono-Regular, Menlo, monospace";
  context.fillText(product.code, padding, padding + 145);
  if (subtitle) {
    context.fillStyle = "#8290a5";
    context.font = "500 15px -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', sans-serif";
    context.fillText(subtitle, padding + 240, padding + 145);
  }

  const mainY = padding + headerHeight + 24;
  const imageX = padding;
  const imageWidth = 430;
  const infoX = imageX + imageWidth + 24;
  const infoWidth = cardWidth - padding - infoX;
  drawRoundedRect(context, imageX, mainY, imageWidth, mainHeight, 18, "#f3f7fd", "#dce6f3");
  drawRoundedRect(context, infoX, mainY, infoWidth, mainHeight, 18, "#f8faff", "#dce6f3");

  try {
    if (!product.image) throw new Error("没有产品主图");
    const image = await loadProductCanvasImage(product.image);
    const maxImageWidth = imageWidth - 34;
    const maxImageHeight = mainHeight - 34;
    const scale = Math.min(maxImageWidth / image.naturalWidth, maxImageHeight / image.naturalHeight);
    const imageWidthOnCanvas = image.naturalWidth * scale;
    const imageHeightOnCanvas = image.naturalHeight * scale;
    context.drawImage(
      image,
      imageX + (imageWidth - imageWidthOnCanvas) / 2,
      mainY + (mainHeight - imageHeightOnCanvas) / 2,
      imageWidthOnCanvas,
      imageHeightOnCanvas,
    );
  } catch {
    context.fillStyle = "#9eb3d3";
    context.font = "800 22px -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', sans-serif";
    context.fillText("GAUDELOT", imageX + 132, mainY + mainHeight / 2);
  }

  context.fillStyle = "#6f809b";
  context.font = "700 15px -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', sans-serif";
  context.fillText("主要参数", infoX + 22, mainY + 31);
  const cellsTop = mainY + 48;
  const cellWidth = (infoWidth - 44 - specGap) / columnCount;
  specs.forEach(([label, value], index) => {
    const column = index % columnCount;
    const row = Math.floor(index / columnCount);
    const cellX = infoX + 22 + column * (cellWidth + specGap);
    const cellY = cellsTop + row * (specCellHeight + specGap);
    drawRoundedRect(context, cellX, cellY, cellWidth, specCellHeight, 10, "#ffffff", "#e4ebf4");
    context.fillStyle = "#8b98ab";
    context.font = "600 13px -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', sans-serif";
    const labelLines = wrapCanvasText(context, label, cellWidth - 24, 1);
    context.fillText(labelLines[0] ?? label, cellX + 12, cellY + 22);
    context.fillStyle = "#15233d";
    context.font = "800 16px -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', sans-serif";
    const valueLines = wrapCanvasText(context, value, cellWidth - 24, 2);
    valueLines.forEach((line, lineIndex) => context.fillText(line, cellX + 12, cellY + 47 + lineIndex * 18));
  });

  context.fillStyle = "#8b98ab";
  context.font = "500 13px -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', sans-serif";
  context.fillText("高徳乐官方产品目录 · 仅供选型参考，具体参数以正式文件为准", padding, cardHeight - padding - 11);

  return new Promise<Blob>((resolve, reject) => {
    canvas.toBlob((blob) => (blob ? resolve(blob) : reject(new Error("PNG生成失败"))), "image/png");
  });
}

export default function Home() {
  const [stage, setStage] = useState(0);
  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
  const [requirements, setRequirements] = useState(DEFAULT_REQUIREMENTS);
  const [showSampleForm, setShowSampleForm] = useState(false);
  const [submitted, setSubmitted] = useState(false);
  const [leadId, setLeadId] = useState("");
  const [catalogQuery, setCatalogQuery] = useState("");
  const [catalogCategory, setCatalogCategory] = useState("全部产品");
  const [catalogScale, setCatalogScale] = useState("all");
  const [catalogLimit, setCatalogLimit] = useState(24);
  const [catalogToolbarCompact, setCatalogToolbarCompact] = useState(false);
  const [catalogToolbarFiltersOpen, setCatalogToolbarFiltersOpen] = useState(false);
  const [catalogToolbarHidden, setCatalogToolbarHidden] = useState(false);
  const [precisionGearQuery, setPrecisionGearQuery] = useState("");
  const [precisionGearCategory, setPrecisionGearCategory] = useState("全部子类");
  const [precisionGearLimit, setPrecisionGearLimit] = useState(24);
  const [precisionGearToolbarCompact, setPrecisionGearToolbarCompact] = useState(false);
  const [precisionGearFiltersOpen, setPrecisionGearFiltersOpen] = useState(false);
  const [selectedCatalogProduct, setSelectedCatalogProduct] = useState<CatalogProduct | null>(null);
  const [catalogVisualMode, setCatalogVisualMode] = useState<CatalogVisualMode>("main");
  const [savingProductKey, setSavingProductKey] = useState("");
  const [saveProductMessage, setSaveProductMessage] = useState("");

  const matches = useMemo(() => getMatches(requirements), [requirements]);
  const topMatches = matches.slice(0, 3);
  const top = topMatches[0];
  const compatibleCount = matches.filter((match) => match.coreCompatible).length;
  const filteredCatalog = useMemo(() => {
    const query = catalogQuery.trim().toLowerCase();
    return CATALOG_PRODUCTS.filter((product) => {
      const productScale = getProductScale(product)?.key ?? "unmarked";
      if (catalogScale !== "all" && productScale !== catalogScale) return false;
      const matchesCategory =
        catalogCategory === "全部产品" ||
        product.category === catalogCategory ||
        (catalogCategory === SILENT_SERVO_CATEGORY && isSilentServo(product));
      if (!matchesCategory) return false;
      if (!query) return true;
      const haystack = [
        product.name,
        product.code,
        product.category,
        ...Object.keys(product.specs),
        ...Object.values(product.specs),
      ]
        .join(" ")
        .toLowerCase();
      return haystack.includes(query);
    });
  }, [catalogCategory, catalogQuery, catalogScale]);
  const visibleCatalog = filteredCatalog.slice(0, catalogLimit);
  const filteredPrecisionGears = useMemo(() => {
    const query = precisionGearQuery.trim().toLowerCase();
    return PRECISION_GEAR_PRODUCTS.filter((product) => {
      if (precisionGearCategory !== "全部子类" && product.subCategory !== precisionGearCategory) return false;
      if (!query) return true;
      const haystack = [
        product.name,
        product.code,
        product.subCategory,
        ...Object.keys(product.specs),
        ...Object.values(product.specs),
      ].join(" ").toLowerCase();
      return haystack.includes(query);
    });
  }, [precisionGearCategory, precisionGearQuery]);
  const visiblePrecisionGears = filteredPrecisionGears.slice(0, precisionGearLimit);
  const needsEngineer =
    !top?.coreCompatible ||
    requirements.annualVolume === "50000件以上" ||
    Number(requirements.firstOrderQuantity) >= 1000 ||
    requirements.application === "工业设备";
  const selectedCatalogDimensionImage = selectedCatalogProduct
    ? getCatalogProductDimensionImage(selectedCatalogProduct)
    : null;

  useEffect(() => {
    function updateCatalogToolbarState() {
      const toolbar = document.querySelector(".catalog-toolbar");
      const shouldCompact = window.innerWidth <= 720 && Boolean(toolbar) && toolbar.getBoundingClientRect().top <= 72 && window.scrollY > 0;
      setCatalogToolbarCompact((current) => (current === shouldCompact ? current : shouldCompact));
      if (!shouldCompact) setCatalogToolbarFiltersOpen(false);

      const precisionHeading = document.querySelector(".precision-gear-catalog-heading");
      const shouldHideCatalogToolbar = window.innerWidth <= 720 && Boolean(precisionHeading) && precisionHeading.getBoundingClientRect().top <= 72;
      setCatalogToolbarHidden((current) => (current === shouldHideCatalogToolbar ? current : shouldHideCatalogToolbar));

      const precisionToolbar = document.querySelector(".precision-gear-controls");
      const shouldCompactPrecision = window.innerWidth <= 720 && Boolean(precisionToolbar) && precisionToolbar.getBoundingClientRect().top <= 72 && window.scrollY > 0;
      setPrecisionGearToolbarCompact((current) => (current === shouldCompactPrecision ? current : shouldCompactPrecision));
      if (!shouldCompactPrecision) setPrecisionGearFiltersOpen(false);
    }

    updateCatalogToolbarState();
    window.addEventListener("scroll", updateCatalogToolbarState, { passive: true });
    document.addEventListener("scroll", updateCatalogToolbarState, { passive: true, capture: true });
    window.addEventListener("resize", updateCatalogToolbarState);
    return () => {
      window.removeEventListener("scroll", updateCatalogToolbarState);
      document.removeEventListener("scroll", updateCatalogToolbarState, true);
      window.removeEventListener("resize", updateCatalogToolbarState);
    };
  }, []);

  function openCatalogProduct(product: CatalogProduct) {
    setSelectedCatalogProduct(product);
    setCatalogVisualMode("main");
  }

  async function saveProductCard(request: SaveProductRequest) {
    if (savingProductKey) return;
    const saveKey = `${request.product.id}-${request.badge ?? "product"}`;
    setSavingProductKey(saveKey);
    setSaveProductMessage("正在生成产品图片…");

    try {
      const blob = await renderProductCardPng(request);
      const safeName = `${request.product.code}-${request.product.name}`
        .replace(/[\\/:*?"<>|]/g, "-")
        .replace(/\s+/g, "-")
        .slice(0, 90);
      const fileName = `${safeName || request.product.id}.png`;
      const file = new File([blob], fileName, { type: "image/png" });
      const isMobile = /Android|iPhone|iPad|iPod/i.test(navigator.userAgent) ||
        (navigator.maxTouchPoints > 0 && window.innerWidth <= 900);
      const canShareFile = typeof navigator.share === "function" &&
        (!navigator.canShare || navigator.canShare({ files: [file] }));

      if (isMobile && canShareFile) {
        try {
          await navigator.share({
            title: `${request.product.name} 产品资料`,
            text: `高徳乐${request.product.category} · ${request.product.code}`,
            files: [file],
          });
          setSaveProductMessage("已打开系统分享面板");
        } catch (error) {
          if (error instanceof DOMException && error.name === "AbortError") {
            setSaveProductMessage("已取消保存");
          } else {
            throw error;
          }
        }
      } else {
        const url = URL.createObjectURL(blob);
        const anchor = document.createElement("a");
        anchor.href = url;
        anchor.download = fileName;
        document.body.appendChild(anchor);
        anchor.click();
        anchor.remove();
        window.setTimeout(() => URL.revokeObjectURL(url), 1000);
        setSaveProductMessage("PNG图片已下载");
      }
    } catch (error) {
      console.error("保存产品图片失败", error);
      setSaveProductMessage("图片生成失败，请稍后重试");
    } finally {
      setSavingProductKey("");
      window.setTimeout(() => setSaveProductMessage(""), 2800);
    }
  }

  function startSelection() {
    setMobileMenuOpen(false);
    setStage(1);
    requestAnimationFrame(() => {
      document.getElementById("selector")?.scrollIntoView({ behavior: "smooth", block: "start" });
    });
  }

  function update<K extends keyof Requirements>(key: K, value: Requirements[K]) {
    setRequirements((current) => ({ ...current, [key]: value }));
  }

  function reset() {
    setStage(1);
    setRequirements(DEFAULT_REQUIREMENTS);
    setShowSampleForm(false);
    setSubmitted(false);
  }

  function submitLead(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const id = `GDL-${new Date().toISOString().slice(5, 10).replace("-", "")}-${String(
      Date.now(),
    ).slice(-4)}`;
    setLeadId(id);
    setSubmitted(true);
  }

  return (
    <main>
      {saveProductMessage && (
        <div className="product-save-toast" role="status" aria-live="polite">
          {saveProductMessage}
        </div>
      )}
      <header className="site-header">
        <a className="brand" href="#top" aria-label="高德乐 AI选型首页">
          <span className="brand-wordmark">
            <strong>GAUDELOT</strong>
            <small>高德乐</small>
          </span>
        </a>
        <nav id="mobile-primary-nav" className={mobileMenuOpen ? "is-open" : ""} aria-label="主导航">
          <a href="#selector" onClick={() => setMobileMenuOpen(false)}>AI选型</a>
          <a href="#products" onClick={() => setMobileMenuOpen(false)}>完整目录</a>
          <a href="#precision-gears" onClick={() => setMobileMenuOpen(false)}>精密齿轮</a>
          <a href="#how" onClick={() => setMobileMenuOpen(false)}>服务流程</a>
        </nav>
        <div className="header-actions">
          <button className="header-cta" type="button" onClick={startSelection}>
            开始选型 <span>→</span>
          </button>
          <button
            className="mobile-menu-toggle"
            type="button"
            aria-expanded={mobileMenuOpen}
            aria-controls="mobile-primary-nav"
            onClick={() => setMobileMenuOpen((open) => !open)}
          >
            <span aria-hidden="true">{mobileMenuOpen ? "×" : "☰"}</span>
            <small>{mobileMenuOpen ? "关闭" : "菜单"}</small>
          </button>
        </div>
      </header>

      <section className="hero" id="top">
        <div className="hero-copy">
          <div className="eyebrow"><span /> AI 智能选型 · 工程师复核</div>
          <h1>
            3分钟，找到<br />
            <em>适合你的舵机</em>
          </h1>
          <p className="hero-lead">
            告诉我们应用、扭矩与结构限制。AI从高徳乐完整舵机目录中生成候选方案，
            同步准备样品与替代选型摘要。
          </p>
          <div className="hero-actions">
            <button className="primary-action" type="button" onClick={startSelection}>
              免费开始选型 <span>→</span>
            </button>
            <a href="#products" className="text-action">查看能力范围</a>
          </div>
          <div className="trust-row">
            <span><b>280</b> 个产品型号</span>
            <span><b>0.09–920</b> kgf·cm</span>
            <span><b>48h</b> 方案响应</span>
          </div>
        </div>

        <div className="selector-shell" id="selector">
          <div className="selector-topbar">
            <div>
              <span className="live-dot" /> AI 选型助手
            </div>
            <span className="secure-note">仅作初选建议</span>
          </div>

          {stage === 0 && (
            <div className="welcome-panel">
              <div className="assistant-avatar">AI</div>
              <p className="assistant-label">高徳乐选型助手</p>
              <h2>你好，我来帮你缩小选型范围。</h2>
              <p>回答3组问题，即可获得推荐型号、匹配理由和样品申请入口。</p>
              <button className="panel-primary" type="button" onClick={startSelection}>
                开始回答 <span>预计3分钟</span>
              </button>
              <div className="privacy-note">✓ 无需注册即可查看选型结果</div>
            </div>
          )}

          {stage > 0 && stage < 4 && (
            <div className="question-panel">
              <div className="progress-wrap" aria-label={`选型进度 ${stage}/3`}>
                <div className="progress-labels">
                  <span>需求识别</span>
                  <strong>{stage} / 3</strong>
                </div>
                <div className="progress-track"><i style={{ width: `${stage * 33.33}%` }} /></div>
              </div>

              {stage === 1 && (
                <div className="question-step">
                  <p className="step-kicker">第一步 · 使用场景</p>
                  <h2>舵机将用在什么产品上？</h2>
                  <p className="step-help">选择最接近的一项，后续可以补充具体结构。</p>
                  <div className="choice-grid">
                    {APPLICATIONS.map((item) => (
                      <button
                        type="button"
                        key={item.name}
                        className={`choice-card ${requirements.application === item.name ? "selected" : ""}`}
                        onClick={() => update("application", item.name)}
                      >
                        <b>{item.name}</b>
                        <small>{item.note}</small>
                        <span className="choice-check">✓</span>
                      </button>
                    ))}
                  </div>
                </div>
              )}

              {stage === 2 && (
                <div className="question-step">
                  <p className="step-kicker">第二步 · 核心参数</p>
                  <h2>输入舵机的关键技术要求</h2>
                  <p className="step-help">已覆盖243款舵机：0.09–920 kgf·cm，并按官方目录额定电压精确筛选。</p>
                  <div className="two-fields compact-fields">
                    <label className="select-field">
                      <span>目标产品系列</span>
                      <select
                        value={requirements.category}
                        onChange={(event) => update("category", event.target.value)}
                      >
                        <option value="全部舵机">全部舵机（243款）</option>
                        <optgroup label="官方产品系列">
                          {SERVO_CATEGORIES.map((category) => (
                            <option key={category} value={category}>
                              {category}（{getCategoryCount(category)}款）
                            </option>
                          ))}
                        </optgroup>
                        <optgroup label="特色筛选与定制">
                          {[SILENT_SERVO_CATEGORY, CUSTOM_SERVO_CATEGORY].map((category) => (
                            <option key={category} value={category}>
                              {category === CUSTOM_SERVO_CATEGORY
                                ? `${category}（联系我们）`
                                : `${category}（${getCategoryCount(category)}款）`}
                            </option>
                          ))}
                        </optgroup>
                      </select>
                    </label>
                    <label className="select-field">
                      <span>额定电压</span>
                      <select
                        value={requirements.voltage}
                        onChange={(event) => update("voltage", Number(event.target.value))}
                      >
                        {RATED_VOLTAGES.map((voltage) => (
                          <option key={voltage} value={voltage}>{voltage.toFixed(1)}V</option>
                        ))}
                      </select>
                    </label>
                  </div>
                  <div className="field-stack">
                    <div className="field-label">
                      <label htmlFor="torque">最低堵转扭矩</label>
                      <span className="torque-entry">
                        <input
                          aria-label="最低堵转扭矩精确值"
                          type="number"
                          min={TORQUE_MIN}
                          max={TORQUE_MAX}
                          step="0.01"
                          value={requirements.torque}
                          onChange={(event) => update(
                            "torque",
                            Math.min(TORQUE_MAX, Math.max(TORQUE_MIN, Number(event.target.value) || TORQUE_MIN)),
                          )}
                        />
                        <strong>kgf·cm</strong>
                      </span>
                    </div>
                    <input
                      id="torque"
                      className="range-input"
                      type="range"
                      min="0"
                      max="100"
                      step="0.1"
                      value={torqueToSlider(requirements.torque)}
                      onChange={(event) => update("torque", sliderToTorque(Number(event.target.value)))}
                    />
                    <div className="range-scale"><span>0.09</span><span>1</span><span>10</span><span>100</span><span>920</span></div>
                    <div className="torque-presets" aria-label="常用扭矩快捷值">
                      {TORQUE_PRESETS.map((torque) => (
                        <button
                          key={torque}
                          type="button"
                          className={requirements.torque === torque ? "active" : ""}
                          onClick={() => update("torque", torque)}
                        >{formatTorque(torque)}</button>
                      ))}
                    </div>
                  </div>
                  <div className="parameter-grid">
                    <label className="select-field">
                      <span>单只重量上限</span>
                      <select
                        value={requirements.weightLimit}
                        onChange={(event) => update("weightLimit", Number(event.target.value))}
                      >
                        <option value={0}>不限</option>
                        {[2, 5, 10, 20, 40, 100, 250, 500, 1000, 2000].map((weight) => (
                          <option key={weight} value={weight}>{weight}g以内</option>
                        ))}
                      </select>
                    </label>
                    <label className="select-field">
                      <span>操作角度</span>
                      <select
                        value={requirements.angle}
                        onChange={(event) => update("angle", event.target.value)}
                      >
                        <option>不限</option>
                        <option>135°</option>
                        <option>180°</option>
                        <option>270–330°</option>
                        <option>360°/多圈</option>
                      </select>
                    </label>
                    <label className="select-field">
                      <span>控制 / 通讯方式</span>
                      <select
                        value={requirements.control}
                        onChange={(event) => update("control", event.target.value)}
                      >
                        <option>不限</option>
                        <option>PWM/三线</option>
                        <option>串口/TTL</option>
                        <option>RS485</option>
                        <option>CAN</option>
                        <option>SBUS</option>
                        <option>二/四/五线</option>
                      </select>
                    </label>
                    <label className="select-field">
                      <span>齿轮材质</span>
                      <select
                        value={requirements.gear}
                        onChange={(event) => update("gear", event.target.value)}
                      >
                        <option>不限</option>
                        <option>塑胶齿</option>
                        <option>混合齿</option>
                        <option>全金属齿</option>
                      </select>
                    </label>
                  </div>
                </div>
              )}

              {stage === 3 && (
                <div className="question-step">
                  <p className="step-kicker">第三步 · 项目信息</p>
                  <h2>最后，告诉我采购侧的偏好。</h2>
                  <p className="step-help">这些信息用于调整候选型号的优先级，并由工程师在送样前复核。</p>
                  <div className="two-fields">
                    <label className="select-field">
                      <span>预计年度用量</span>
                      <select
                        value={requirements.annualVolume}
                        onChange={(event) => update("annualVolume", event.target.value)}
                      >
                        <option>500件以内</option>
                        <option>500–5000件</option>
                        <option>5000–50000件</option>
                        <option>50000件以上</option>
                      </select>
                    </label>
                    <label className="select-field">
                      <span>首次采购数量（只）</span>
                      <input
                        className="parameter-input"
                        type="number"
                        min="1"
                        step="1"
                        inputMode="numeric"
                        value={requirements.firstOrderQuantity}
                        onChange={(event) => update("firstOrderQuantity", event.target.value)}
                        placeholder="例如：500"
                      />
                    </label>
                  </div>
                  <div className="two-fields">
                    <label className="select-field">
                      <span>最想解决的问题</span>
                      <select
                        value={requirements.painPoint}
                        onChange={(event) => update("painPoint", event.target.value)}
                      >
                        <option>交期</option>
                        <option>成本</option>
                        <option>耐久</option>
                        <option>体积</option>
                        <option>一致性</option>
                        <option>二供替代</option>
                      </select>
                    </label>
                    <label className="select-field">
                      <span>当前使用型号（选填）</span>
                      <input
                        className="parameter-input"
                        value={requirements.currentModel}
                        onChange={(event) => update("currentModel", event.target.value)}
                        placeholder="例如：SG90 / DS-E001"
                      />
                    </label>
                  </div>
                  <label className="text-field project-notes">
                    <span>其他要求备注（选填）</span>
                    <textarea
                      value={requirements.otherRequirements}
                      onChange={(event) => update("otherRequirements", event.target.value)}
                      placeholder="例如：防水等级、噪音、寿命、认证、安装尺寸、线长或交期要求"
                    />
                  </label>
                </div>
              )}

              <div className="panel-nav">
                <button className="back-button" type="button" onClick={() => setStage(stage - 1)}>← 返回</button>
                <button
                  className="next-button"
                  type="button"
                  disabled={stage === 1 && !requirements.application}
                  onClick={() => setStage(stage + 1)}
                >
                  {stage === 3 ? "生成选型方案" : "继续"} <span>→</span>
                </button>
              </div>
            </div>
          )}

          {stage === 4 && requirements.category === CUSTOM_SERVO_CATEGORY && (
            <div className="result-panel custom-result-panel">
              <div className="result-heading">
                <div>
                  <p className="step-kicker">非标准舵机定制</p>
                  <h2>已生成定制需求摘要</h2>
                </div>
                <button type="button" className="restart-button" onClick={reset}>重新填写</button>
              </div>

              <div className="custom-result-card">
                <div className="custom-result-mark">ODM</div>
                <div>
                  <span>高徳乐工程定制</span>
                  <h3>目录型号无法覆盖？可进行非标结构与性能评估</h3>
                  <p>支持特殊尺寸、扭矩、角度、控制协议、静音、防水、线材与安装结构等定制需求。</p>
                </div>
                <div className="metric-grid custom-requirement-grid">
                  <Metric label="最低堵转扭矩" value={`${formatTorque(requirements.torque)} kgf·cm`} />
                  <Metric label="额定电压" value={`${requirements.voltage.toFixed(1)}V`} />
                  <Metric label="操作角度" value={requirements.angle} />
                  <Metric label="控制 / 通讯" value={requirements.control} />
                  <Metric label="首次采购数量" value={requirements.firstOrderQuantity ? `${requirements.firstOrderQuantity}只` : "待确认"} />
                  <Metric label="年度用量" value={requirements.annualVolume} />
                </div>
                {requirements.otherRequirements && (
                  <p className="custom-notes"><strong>其他要求：</strong>{requirements.otherRequirements}</p>
                )}
              </div>

              {!showSampleForm && (
                <div className="result-actions">
                  <button className="panel-primary" type="button" onClick={() => setShowSampleForm(true)}>
                    联系我们 · 提交定制需求 <span>→</span>
                  </button>
                  <button className="outline-button" type="button" onClick={() => window.print()}>打印 / 保存需求</button>
                </div>
              )}

              {showSampleForm && !submitted && (
                <form className="sample-form custom-contact-form" onSubmit={submitLead}>
                  <div>
                    <p className="step-kicker">联系我们</p>
                    <h3>留下项目联系方式</h3>
                    <p>提交后将生成定制需求卡，正式版可自动进入CRM并通知工程师跟进。</p>
                  </div>
                  <div className="form-grid">
                    <label><span>公司名称</span><input required name="company" placeholder="请输入公司名称" /></label>
                    <label><span>联系人</span><input required name="name" placeholder="姓名" /></label>
                    <label><span>手机号</span><input required name="phone" inputMode="tel" placeholder="用于方案确认" /></label>
                    <label><span>邮箱（选填）</span><input name="email" type="email" placeholder="接收定制方案" /></label>
                  </div>
                  <label className="full-field">
                    <span>补充说明</span>
                    <textarea name="notes" defaultValue={requirements.otherRequirements} placeholder="请补充结构图、安装空间、认证或交期要求" />
                  </label>
                  <button className="panel-primary" type="submit">提交定制需求 <span>→</span></button>
                  <small className="demo-disclaimer">当前为内部演示，不会向外部系统发送信息。</small>
                </form>
              )}

              {submitted && (
                <div className="success-card">
                  <div className="success-icon">✓</div>
                  <p className="step-kicker">定制需求卡已生成</p>
                  <h3>需求编号 {leadId}</h3>
                  <p>需求已标记为“非标准舵机定制”。正式版上线后将自动通知销售与工程师联合评估。</p>
                  <button type="button" className="outline-button" onClick={reset}>继续填写另一项需求</button>
                </div>
              )}
            </div>
          )}

          {stage === 4 && requirements.category !== CUSTOM_SERVO_CATEGORY && top && (
            <div className="result-panel">
              <div className="result-heading">
                <div>
                  <p className="step-kicker">AI 初选结果</p>
                  <h2>{compatibleCount > 0 ? `找到 ${compatibleCount} 个匹配型号` : "暂无完全匹配型号"}</h2>
                </div>
                <button type="button" className="restart-button" onClick={reset}>重新选型</button>
              </div>

              <div className="recommendation-grid">
                {topMatches.map((match, index) => (
                  <article className={`recommendation-card ${index === 0 ? "is-primary" : ""}`} key={match.product.id}>
                    <button
                      type="button"
                      className="recommendation-image-wrap"
                      onClick={() => openCatalogProduct(match.product)}
                      aria-label={`查看${match.product.name}大图`}
                    >
                      <img src={match.product.image} alt={match.product.name} />
                      <span className="match-badge">
                        {index === 0 ? (match.coreCompatible ? "首选推荐" : "待复核候选") : `${match.confidence}% 匹配`}
                      </span>
                      <span className="recommendation-zoom-hint">点击查看大图</span>
                    </button>
                    <div className="recommendation-content">
                      <p className="product-code">{match.product.code}</p>
                      <h3>{match.product.name}</h3>
                      <p className="product-subtitle">{match.product.category} · {match.product.size || "尺寸待复核"}</p>
                      <div className="metric-grid">
                        <Metric label="堵转扭矩" value={`${formatTorque(match.product.torque)} kgf·cm`} />
                        <Metric label="电压范围" value={`${match.product.voltageMin}–${match.product.voltageMax}V`} />
                        <Metric label="空载速度" value={match.product.speed || "目录未标注"} />
                        <Metric label="操作角度" value={match.product.angle || "目录未标注"} />
                        <Metric label="控制 / 通讯" value={match.product.control || "目录未标注"} />
                        <Metric label="齿轮材质" value={match.product.gear} />
                      </div>
                      <ul className="reason-list">
                        {match.reasons.slice(0, 2).map((reason) => <li key={reason}>✓ {reason}</li>)}
                      </ul>
                      <div className="source-line">
                        <span>官方目录型号</span>
                        <strong>{match.product.category}</strong>
                        <small>价格与交期按用量确认</small>
                      </div>
                      <button
                        className={`product-save-button ${savingProductKey.startsWith(`${match.product.id}-`) ? "is-saving" : ""}`}
                        type="button"
                        onClick={() => saveProductCard({
                          product: match.product,
                          badge: index === 0 ? (match.coreCompatible ? "首选推荐" : "待复核候选") : `${match.confidence}% 匹配`,
                          subtitle: `${match.product.category} · ${match.product.size || "尺寸待复核"}`,
                          extraSpecs: [["AI匹配度", `${match.confidence}%`]],
                        })}
                        aria-label={`保存${match.product.name}产品图片`}
                      >
                        {savingProductKey.startsWith(`${match.product.id}-`) ? "正在生成…" : "保存产品"} <span>↓</span>
                      </button>
                    </div>
                  </article>
                ))}
              </div>

              {needsEngineer && (
                <div className="engineer-alert">
                  <span>工程师复核</span>
                  <p>{compatibleCount === 0
                    ? "当前条件没有完全匹配的目录型号，建议调整电压、扭矩余量或发起定制评估。"
                    : "你的项目包含高用量、工业场景或边界参数，系统已标记为优先人工复核。"}</p>
                </div>
              )}

              {!showSampleForm && (
                <div className="result-actions">
                  <button className="panel-primary" type="button" onClick={() => setShowSampleForm(true)}>
                    申请样品与工程师复核 <span>→</span>
                  </button>
                  <button className="outline-button" type="button" onClick={() => window.print()}>打印 / 保存方案</button>
                </div>
              )}

              {showSampleForm && !submitted && (
                <form className="sample-form" onSubmit={submitLead}>
                  <div>
                    <p className="step-kicker">样品申请</p>
                    <h3>留下项目联系方式</h3>
                    <p>演示版会生成一张线索卡；正式版可接入CRM、企微或商城订单。</p>
                  </div>
                  <div className="form-grid">
                    <label><span>公司名称</span><input required name="company" placeholder="请输入公司名称" /></label>
                    <label><span>联系人</span><input required name="name" placeholder="姓名" /></label>
                    <label><span>手机号</span><input required name="phone" inputMode="tel" placeholder="用于样品确认" /></label>
                    <label><span>样品数量</span><select name="quantity"><option>1–2只</option><option>3–5只</option><option>6–10只</option></select></label>
                  </div>
                  <label className="full-field"><span>补充说明</span><textarea name="notes" placeholder="安装尺寸、线长、角度、控制协议或测试时间要求" /></label>
                  <button className="panel-primary" type="submit">生成样品申请单 <span>→</span></button>
                  <small className="demo-disclaimer">当前为内部演示，不会向外部系统发送信息。</small>
                </form>
              )}

              {submitted && (
                <div className="success-card">
                  <div className="success-icon">✓</div>
                  <p className="step-kicker">线索卡已生成</p>
                  <h3>申请编号 {leadId}</h3>
                  <p>推荐型号：{top.product.name}。正式版上线后，此处将自动进入CRM并触发技术复核。</p>
                  <button type="button" className="outline-button" onClick={reset}>继续测试另一组需求</button>
                </div>
              )}
            </div>
          )}
        </div>
      </section>

      <section className="capability-strip" aria-label="高徳乐能力">
        <div><strong>2万㎡</strong><span>研发与制造基地</span></div>
        <div><strong>137台</strong><span>精密注塑设备</span></div>
        <div><strong>1万台/天</strong><span>单线自动化产能</span></div>
        <div><strong>IATF 16949</strong><span>汽车行业质量体系</span></div>
      </section>

      <section className="products-section" id="products">
        <div className="section-heading">
          <div>
            <p className="eyebrow"><span /> 官方产品目录 · 2026.06</p>
            <h2>完整收录{CATALOG_PRODUCTS.length}个产品型号</h2>
          </div>
          <p>官方目录按八个主分类收录{CATALOG_PRODUCTS.length}款产品；静音舵机作为特色子集筛选，不重复计入产品总数。</p>
        </div>

        <div className="catalog-directory">
        <div className="catalog-summary" aria-label="产品分类统计">
          {PRIMARY_CATALOG_CATEGORIES.map((category) => (
            <button
              type="button"
              key={category}
              className={catalogCategory === category ? "active" : ""}
              onClick={() => {
                setCatalogCategory(category);
                setCatalogLimit(24);
              }}
            >
              <strong>{getCategoryCount(category)}</strong>
              <span>{category}</span>
            </button>
          ))}
        </div>
        <p className="catalog-category-note">分类已按官方目录表头及业务规则复核 · 八个主分类合计{CATALOG_PRODUCTS.length}款 · 舵盘配件6款 · 静音舵机11款为标准舵机特色子集</p>

        <div className={`catalog-toolbar ${catalogToolbarCompact ? "is-compact" : ""} ${catalogToolbarFiltersOpen ? "filters-open" : ""} ${catalogToolbarHidden ? "is-hidden" : ""}`}>
          <label className="catalog-search">
            <span>⌕</span>
            <input
              value={catalogQuery}
              onChange={(event) => {
                setCatalogQuery(event.target.value);
                setCatalogLimit(24);
              }}
              placeholder="搜索型号、编码、扭矩、协议或参数"
              aria-label="搜索产品目录"
            />
            {catalogQuery && (
              <button type="button" onClick={() => setCatalogQuery("")} aria-label="清空搜索">×</button>
            )}
          </label>
          <button
            className="catalog-mobile-filter-toggle"
            type="button"
            aria-expanded={catalogToolbarFiltersOpen}
            onClick={() => setCatalogToolbarFiltersOpen((open) => !open)}
          >
            {catalogToolbarFiltersOpen ? "收起" : "筛选"}
          </button>
          <div className="category-pills" aria-label="产品类别筛选">
            {CATALOG_FILTER_CATEGORIES.map((category) => (
              <button
                type="button"
                key={category}
                className={`${catalogCategory === category ? "active" : ""} ${category === SILENT_SERVO_CATEGORY ? "feature-filter" : ""}`}
                onClick={() => {
                  setCatalogCategory(category);
                  setCatalogLimit(24);
                }}
              >{category === SILENT_SERVO_CATEGORY ? `${category} · ${SILENT_SERVO_COUNT}` : category}</button>
            ))}
          </div>
          <div className="catalog-scale-filter">
            <label>
              <span>按 g / kg 型号规格筛选</span>
              <select
                value={catalogScale}
                onChange={(event) => {
                  setCatalogScale(event.target.value);
                  setCatalogLimit(24);
                }}
              >
                <option value="all">全部 g / kg 规格</option>
                <optgroup label="克重系列（g / 克）">
                  {GRAM_SCALE_OPTIONS.map((option) => (
                    <option key={option.key} value={option.key}>{option.label}（{option.count}款）</option>
                  ))}
                </optgroup>
                <optgroup label="千克扭矩等级（kg / 千克）">
                  {KILOGRAM_SCALE_OPTIONS.map((option) => (
                    <option key={option.key} value={option.key}>{option.label}（{option.count}款）</option>
                  ))}
                </optgroup>
                <option value="unmarked">其他未标注 g/kg（{UNMARKED_SCALE_COUNT}款）</option>
              </select>
            </label>
            <p><strong>说明：</strong>g/克表示产品克重系列；kg/Kg通常表示舵机扭矩等级，并非产品自身重量。</p>
          </div>
          <p className="catalog-result-count">
            找到 <strong>{filteredCatalog.length}</strong> 个型号
          </p>
        </div>

        {visibleCatalog.length > 0 ? (
          <div className="catalog-grid">
            {visibleCatalog.map((product) => (
              <article className="catalog-card" key={product.id}>
                <button
                  type="button"
                  className="catalog-image-button"
                  onClick={() => openCatalogProduct(product)}
                  aria-label={`查看${product.name}详情`}
                >
                  {product.image ? (
                    <img src={product.image} alt={product.name} loading="lazy" />
                  ) : (
                    <span className="catalog-placeholder">GAUDELOT</span>
                  )}
                  <small>{product.category}</small>
                </button>
                <div className="catalog-card-body">
                  <p>{product.code}</p>
                  <h3>{product.name}</h3>
                  <dl>
                    {getFeaturedSpecs(product).map(([label, value]) => (
                      <div key={label}><dt>{label}</dt><dd>{value}</dd></div>
                    ))}
                  </dl>
                  <button type="button" onClick={() => openCatalogProduct(product)}>
                    查看完整参数 <span>→</span>
                  </button>
                  <button
                    className={`product-save-button ${savingProductKey === `${product.id}-${product.category}` ? "is-saving" : ""}`}
                    type="button"
                    onClick={() => saveProductCard({
                      product,
                      badge: product.category,
                      subtitle: "完整产品参数",
                    })}
                    aria-label={`保存${product.name}产品图片`}
                  >
                    {savingProductKey === `${product.id}-${product.category}` ? "正在生成…" : "保存产品"} <span>↓</span>
                  </button>
                </div>
              </article>
            ))}
          </div>
        ) : (
          <div className="catalog-empty">
            <strong>没有找到匹配型号</strong>
            <p>可以尝试减少关键词，或切换到“全部产品”。</p>
            <button type="button" onClick={() => { setCatalogQuery(""); setCatalogCategory("全部产品"); setCatalogScale("all"); }}>
              清除筛选
            </button>
          </div>
        )}

        {catalogLimit < filteredCatalog.length && (
          <div className="load-more-wrap">
            <button type="button" onClick={() => setCatalogLimit((current) => current + 24)}>
              加载更多产品 <span>已显示 {visibleCatalog.length} / {filteredCatalog.length}</span>
            </button>
          </div>
        )}
        </div>

        <p className="eyebrow precision-gear-section-label"><span /> 精密齿轮</p>
        <div className="precision-gear-catalog" id="precision-gears" aria-label="精密齿轮配件产品卡片">
          <div className="precision-gear-catalog-heading">
            <div>
              <p className="step-kicker">产品卡片目录</p>
              <h4>精密齿轮配件 · 511 款</h4>
            </div>
            <p>小型卡片展示型号、子类和关键规格，点击图片可查看产品大图与完整参数。</p>
          </div>
          <div className={`precision-gear-controls ${precisionGearToolbarCompact ? "is-compact" : ""} ${precisionGearFiltersOpen ? "filters-open" : ""}`}>
            <input
              value={precisionGearQuery}
              onChange={(event) => {
                setPrecisionGearQuery(event.target.value);
                setPrecisionGearLimit(24);
              }}
              placeholder="搜索齿轮名称、编码、材质或规格"
              aria-label="搜索精密齿轮配件"
            />
            <button
              className="precision-gear-mobile-filter-toggle"
              type="button"
              aria-expanded={precisionGearFiltersOpen}
              onClick={() => setPrecisionGearFiltersOpen((open) => !open)}
            >
              {precisionGearFiltersOpen ? "收起" : "筛选"}
            </button>
            <div className="precision-gear-pills" aria-label="精密齿轮子类筛选">
              <button
                type="button"
                className={precisionGearCategory === "全部子类" ? "active" : ""}
                onClick={() => {
                  setPrecisionGearCategory("全部子类");
                  setPrecisionGearLimit(24);
                }}
              >全部子类 · 511</button>
              {PRECISION_GEAR_SUBCATEGORIES.map(([name, count]) => (
                <button
                  type="button"
                  key={name}
                  className={precisionGearCategory === name ? "active" : ""}
                  onClick={() => {
                    setPrecisionGearCategory(name);
                    setPrecisionGearLimit(24);
                  }}
                >{name} · {count}</button>
              ))}
            </div>
            <p className="precision-gear-result">找到 <strong>{filteredPrecisionGears.length}</strong> 款配件</p>
          </div>

          {visiblePrecisionGears.length > 0 ? (
            <div className="precision-gear-grid">
              {visiblePrecisionGears.map((product) => (
                <article className="precision-gear-card" key={product.id}>
                  <button
                    type="button"
                    className="precision-gear-image"
                    onClick={() => openCatalogProduct(product)}
                    aria-label={`查看${product.name}大图`}
                  >
                    <img src={product.image} alt={product.name} loading="lazy" />
                    <span>点击查看大图</span>
                  </button>
                  <div className="precision-gear-card-body">
                    <p>{product.subCategory}</p>
                    <h5>{product.name}</h5>
                    <code>{product.code}</code>
                    <dl>
                      {getPrecisionGearCardSpecs(product).map(([label, value]) => (
                        <div key={label}><dt>{label}</dt><dd>{value}</dd></div>
                      ))}
                    </dl>
                    <button
                      className={`product-save-button ${savingProductKey === `${product.id}-${product.subCategory}` ? "is-saving" : ""}`}
                      type="button"
                      onClick={() => saveProductCard({
                        product,
                        badge: "精密齿轮配件",
                        subtitle: product.subCategory,
                        extraSpecs: [["产品子类", product.subCategory]],
                      })}
                      aria-label={`保存${product.name}产品图片`}
                    >
                      {savingProductKey === `${product.id}-${product.subCategory}` ? "正在生成…" : "保存产品"} <span>↓</span>
                    </button>
                  </div>
                </article>
              ))}
            </div>
          ) : (
            <div className="catalog-empty precision-gear-empty">
              <strong>没有找到匹配的精密齿轮</strong>
              <p>可以尝试减少关键词，或切换到“全部子类”。</p>
              <button type="button" onClick={() => { setPrecisionGearQuery(""); setPrecisionGearCategory("全部子类"); setPrecisionGearLimit(24); }}>
                清除筛选
              </button>
            </div>
          )}

          {precisionGearLimit < filteredPrecisionGears.length && (
            <div className="load-more-wrap precision-gear-load-more">
              <button type="button" onClick={() => setPrecisionGearLimit((current) => current + 24)}>
                加载更多齿轮配件 <span>已显示 {visiblePrecisionGears.length} / {filteredPrecisionGears.length}</span>
              </button>
            </div>
          )}
        </div>
      </section>

      {selectedCatalogProduct && (
        <div
          className="catalog-modal-backdrop"
          role="presentation"
          onMouseDown={(event) => {
            if (event.target === event.currentTarget) setSelectedCatalogProduct(null);
          }}
        >
          <section
            className="catalog-modal"
            role="dialog"
            aria-modal="true"
            aria-labelledby="catalog-modal-title"
          >
            <button
              className="catalog-modal-close"
              type="button"
              onClick={() => setSelectedCatalogProduct(null)}
              aria-label="关闭产品详情"
            >×</button>
            <div className="catalog-modal-product">
              <div className="catalog-modal-visual-card">
                <div className="catalog-modal-visual-toolbar">
                  <div className="catalog-modal-gallery-switch" role="tablist" aria-label="切换产品图片">
                    <button
                      type="button"
                      className={catalogVisualMode === "main" ? "active" : ""}
                      onClick={() => setCatalogVisualMode("main")}
                      role="tab"
                      aria-selected={catalogVisualMode === "main"}
                    >产品主图</button>
                    <button
                      type="button"
                      className={catalogVisualMode === "size" ? "active" : ""}
                      onClick={() => setCatalogVisualMode("size")}
                      disabled={!selectedCatalogDimensionImage}
                      role="tab"
                      aria-selected={catalogVisualMode === "size"}
                    >产品尺寸</button>
                  </div>
                  <div className="catalog-modal-inline-info">
                    <span>{selectedCatalogProduct.category}</span>
                    <h2 id="catalog-modal-title">{selectedCatalogProduct.name}</h2>
                    <code>{selectedCatalogProduct.code}</code>
                    <small>
                      {selectedCatalogProduct.page > 0
                        ? `官方产品目录第 ${selectedCatalogProduct.page} 页`
                        : selectedCatalogProduct.category === "舵盘配件"
                          ? "商城产品资料 · 舵盘配件"
                          : "商城产品资料 · 精密齿轮配件"}
                    </small>
                  </div>
                </div>
                <div className="catalog-modal-image">
                  {catalogVisualMode === "size" && selectedCatalogDimensionImage ? (
                    <img src={selectedCatalogDimensionImage} alt={`${selectedCatalogProduct.name} 产品尺寸`} />
                  ) : selectedCatalogProduct.image ? (
                    <img src={selectedCatalogProduct.image} alt={selectedCatalogProduct.name} />
                  ) : (
                    <span className="catalog-placeholder">GAUDELOT</span>
                  )}
                </div>
              </div>
            </div>
            <div className="catalog-spec-table">
              {Object.entries(selectedCatalogProduct.specs).map(([label, value]) => (
                <div key={label}><span>{label}</span><strong>{value}</strong></div>
              ))}
            </div>
            <div className="catalog-modal-actions">
              <button
                className="panel-primary"
                type="button"
                onClick={() => {
                  setSelectedCatalogProduct(null);
                  setStage(1);
                  window.scrollTo({ top: 0, behavior: "smooth" });
                }}
              >
                用AI继续确认需求 <span>→</span>
              </button>
              <button
                className={`product-save-button modal-save-button ${savingProductKey === `${selectedCatalogProduct.id}-${selectedCatalogProduct.category}` ? "is-saving" : ""}`}
                type="button"
                onClick={() => saveProductCard({
                  product: selectedCatalogProduct,
                  badge: selectedCatalogProduct.category,
                  subtitle: "完整产品参数",
                })}
                aria-label={`保存${selectedCatalogProduct.name}产品图片`}
              >
                {savingProductKey === `${selectedCatalogProduct.id}-${selectedCatalogProduct.category}` ? "正在生成…" : "保存产品"} <span>↓</span>
              </button>
              <p>具体价格、交期及最终适配结果以工程师确认和正式文件为准。</p>
            </div>
          </section>
        </div>
      )}

      <section className="how-section" id="how">
        <div className="how-copy">
          <p className="eyebrow light"><span /> 无人销售边界</p>
          <h2>标准需求自动完成，<br />复杂项目及时接管。</h2>
          <p>AI负责需求采集、初选、说明和线索评分。工程师负责最终适配、认证和技术承诺，销售负责大客户商业条件。</p>
          <button className="primary-action light-button" type="button" onClick={() => { setStage(1); window.scrollTo({ top: 0, behavior: "smooth" }); }}>
            体验完整流程 <span>→</span>
          </button>
        </div>
        <div className="flow-list">
          <div><b>01</b><span><strong>客户自助描述需求</strong><small>应用、参数、数量和现用型号</small></span></div>
          <div><b>02</b><span><strong>AI生成候选方案</strong><small>匹配理由、参考价格和风险提示</small></span></div>
          <div><b>03</b><span><strong>标准样品自动申请</strong><small>形成结构化线索卡和跟进计划</small></span></div>
          <div><b>04</b><span><strong>复杂项目人工接管</strong><small>技术复核、测试、报价和量产</small></span></div>
        </div>
      </section>

      <footer>
        <div className="brand footer-brand">
          <span className="brand-wordmark"><strong>GAUDELOT</strong><small>高德乐</small></span>
        </div>
        <p>AI选型结果仅供初步筛选，最终型号、价格、交期与适配结果以工程师和正式文件确认为准。</p>
        <span>内部原型 · V1</span>
      </footer>
    </main>
  );
}
