import { useEffect, useMemo, useRef, useState } from "react"
import { Link, useNavigate, useParams, useSearchParams } from "react-router-dom"
import { ArrowLeft, CheckCircle2, ChevronRight, Minus, Plus, Zap } from "lucide-react"
import { Col, InputNumber, Row, Slider as AntSlider, Typography } from "antd"
import { fetchCategories, fetchGroups, fetchProducts, type StoreCategory, type StoreConfigField, type StoreGroup, type StoreProduct, type StorePricing, type StoreProvisionPurchaseField } from "../api/store"
import { addCartItem } from "../api/cart"
import { toast } from "../utils/toast"
import { useAuth } from "../contexts/AuthContext"
import { osLogoOrNull } from "../utils/osLogo"

// ─── 常量 ────────────────────────────────────────────────────────────────────

const CYCLE_LABEL: Record<string, string> = {
  hourly: "小时",
  daily: "天",
  monthly: "月",
  quarterly: "季度",
  semi_annually: "半年",
  annually: "年",
  biennially: "两年",
  triennially: "三年",
  one_time: "一次性",
}

const STORE_HERO_IMAGE = "https://prolxy.com/skin/skyblue/images/server-inside-back.jpg"
const { Text: AntText } = Typography

// ─── 工具函数 ─────────────────────────────────────────────────────────────────

function parseNumber(s: string | null | undefined): number | null {
  if (!s) return null
  const m = s.trim().match(/^([\d.]+)/)
  if (!m) return null
  const n = parseFloat(m[1])
  return isNaN(n) ? null : n
}

function parseBandwidth(s: string | null | undefined): { up: number | null; down: number | null } {
  if (!s) return { up: null, down: null }
  const parts = s.split("/")
  if (parts.length >= 2) {
    return { up: parseNumber(parts[0]), down: parseNumber(parts[1]) }
  }
  const v = parseNumber(s)
  return { up: v, down: v }
}

function decimalPlaces(value: number): number {
  if (!Number.isFinite(value)) return 0
  const text = String(value)
  if (!text.includes(".")) return 0
  return text.split(".")[1]?.length ?? 0
}

// provision_config 里按 def 前缀找字段
function findConfig(fields: StoreConfigField[], key: string): StoreConfigField | undefined {
  return fields.find((f) => f.def.split("|")[0].trim() === key)
}

type StoreOsOption = { label: string; value: number | string }

function splitOptionDef(value: string | null | undefined) {
  const text = String(value ?? "").trim()
  const index = text.indexOf("|")
  if (index < 0) return { value: text, label: text }
  const rawLabel = text.slice(index + 1).trim()
  const labelParts = rawLabel.split("^").filter(Boolean)
  return {
    value: text.slice(0, index).trim(),
    label: rawLabel.includes("^") ? labelParts[labelParts.length - 1] ?? rawLabel : rawLabel,
  }
}

function productOsOptions(product: StoreProduct | null): StoreOsOption[] {
  const osField = findConfig(product?.provision_config ?? [], "os")
  if (!osField) return []
  if (osField.type === "fixed" && osField.value !== null && osField.value !== undefined && osField.value !== "") {
    const parsed = splitOptionDef(`${osField.value}|${osField.def.split("|")[1] ?? osField.value}`)
    return [{ value: parsed.value || String(osField.value), label: parsed.label || String(osField.value) }]
  }
  if (osField.type !== "user_select") return []
  return (osField.options ?? [])
    .map((option) => splitOptionDef(option.def))
    .filter((option) => option.value && option.label)
}

// 最低启用价格
function minPricing(product: StoreProduct): StorePricing | null {
  const enabled = product.pricings.filter((p) => p.is_enabled)
  if (!enabled.length) return null
  return enabled.reduce((a, b) => (a.price < b.price ? a : b))
}

function isOutOfStock(product: StoreProduct | null): boolean {
  return !!product && product.stock_policy === "tracked" && (product.stock ?? 0) <= 0
}

function stockLabel(product: StoreProduct): string {
  if (product.stock_policy !== "tracked") return "库存充足"
  return (product.stock ?? 0) <= 0 ? "已售罄" : `剩余 ${product.stock} 台`
}

function isPluginProvisionProduct(product: StoreProduct | null): boolean {
  if (!product) return false
  if (product.api_type === "plugin") return true
  if (product.provision_plugin || product.product_page) return true
  if (product.api_identifier === "mengnai_bt" || product.sku === "mnbt") return true
  return false
}

function pluginPurchaseFields(product: StoreProduct | null): StoreProvisionPurchaseField[] {
  if (!isPluginProvisionProduct(product)) return []
  return product?.product_page?.purchase_fields ?? product?.provision_plugin?.product_page?.purchase_fields ?? []
}

function pluginFieldDefaultValue(field: StoreProvisionPurchaseField) {
  if (field.default !== undefined) return field.default
  if (field.type === "checkbox") return false
  return ""
}

function defaultPluginFieldValues(product: StoreProduct | null) {
  const values: Record<string, unknown> = {}
  for (const field of pluginPurchaseFields(product)) {
    values[field.key] = pluginFieldDefaultValue(field)
  }
  return values
}

function isPluginFieldEmpty(value: unknown) {
  return value === null || value === undefined || value === ""
}

function productMinQuantity(product: StoreProduct): number {
  return Math.max(1, product.min_quantity ?? 1)
}

function productMaxQuantity(product: StoreProduct): number {
  const maxQuantity = product.max_quantity ?? 0
  if (product.stock_policy !== "tracked") return maxQuantity
  const stock = Math.max(0, product.stock ?? 0)
  return maxQuantity > 0 ? Math.min(maxQuantity, stock) : stock
}

function clampProductQuantity(product: StoreProduct, value: number): number {
  const min = productMinQuantity(product)
  if (isOutOfStock(product)) return min
  const max = productMaxQuantity(product)
  const next = Math.max(min, value)
  return max > 0 ? Math.min(max, next) : next
}

function sortStoreProducts(products: StoreProduct[]): StoreProduct[] {
  return [...products].sort((a, b) => {
    if (a.sort_order !== b.sort_order) return a.sort_order - b.sort_order
    if ((a.vcpu ?? 0) !== (b.vcpu ?? 0)) return (a.vcpu ?? 0) - (b.vcpu ?? 0)
    const am = parseFloat(a.memory ?? "0")
    const bm = parseFloat(b.memory ?? "0")
    return am - bm
  })
}

function defaultSliderValues(product: StoreProduct | null): Record<string, number> {
  const defaults: Record<string, number> = {}
  for (const f of product?.provision_config ?? []) {
    if (f.type === "slider") {
      const key = f.def.split("|")[0].trim()
      defaults[key] = f.slider_min ?? 0
    }
  }
  return defaults
}

// slider 附加费用
function sliderExtra(field: StoreConfigField, val: number): number {
  const min = field.slider_min ?? 0
  const unitPrice = field.slider_unit_price ?? 0
  return Math.max(0, val - min) * unitPrice
}

// ─── 子组件：滑块 ─────────────────────────────────────────────────────────────

function SliderField({
  field,
  value,
  onChange,
}: {
  field: StoreConfigField
  value: number
  onChange: (v: number) => void
}) {
  const min = field.slider_min ?? 0
  const max = field.slider_max ?? 100
  const step = field.slider_step ?? 1
  const unit = field.slider_unit ?? ""
  const label = field.def.includes("|") ? field.def.split("|")[1] : field.def

  // 计算进度百分比用于自定义滑块背景
  const percentage = max > min ? ((value - min) / (max - min)) * 100 : 0

  return (
    <div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-6">
      {/* 左侧：标题 */}
      <div className="w-32 shrink-0">
        <span className="text-sm font-medium text-gray-700">{label}</span>
      </div>

      {/* 中间：滑块区域 */}
      <div className="flex-1 flex flex-col gap-1 relative mt-2 sm:mt-0">
        <div className="flex items-center gap-2">
          <span className="text-[11px] text-gray-400 font-medium shrink-0 w-14 text-right">{min} {unit}</span>
          <div className="relative flex-1 flex items-center h-8">
            <input
              type="range"
              min={min}
              max={max}
              step={step}
              value={value}
              onChange={(e) => onChange(Number(e.target.value))}
              className="absolute z-20 w-full h-full opacity-0 cursor-pointer"
            />
            <div className="absolute z-0 w-full h-1.5 bg-gray-100 rounded-full" />
            <div
              className="absolute z-10 h-1.5 bg-sky-500 rounded-full pointer-events-none transition-all duration-150 ease-out"
              style={{ width: `${percentage}%` }}
            />
            <div
              className="absolute z-10 w-5 h-5 bg-white border-2 border-sky-500 rounded-full shadow-md pointer-events-none transition-all duration-150 ease-out"
              style={{ left: `calc(${percentage}% - 10px)` }}
            />
          </div>
          <span className="text-[11px] text-gray-400 font-medium shrink-0 w-10">{max} {unit}</span>
        </div>
      </div>

      {/* 右侧：步进输入框 */}
      <div className="flex shrink-0 items-center overflow-hidden rounded-lg border border-gray-200 bg-white focus-within:border-sky-400 focus-within:ring-1 focus-within:ring-sky-400 transition-all h-9">
        <button
          type="button"
          onClick={() => onChange(Math.max(min, value - step))}
          className="flex h-full w-8 items-center justify-center bg-gray-50 text-gray-500 hover:bg-gray-100 hover:text-gray-700 active:bg-gray-200 transition-colors"
        >
          <Minus className="h-3.5 w-3.5" />
        </button>
        <div className="flex h-full w-16 items-center justify-center border-x border-gray-200 text-sm font-semibold text-gray-800">
          {value} <span className="ml-1 text-xs text-gray-500 font-normal">{unit}</span>
        </div>
        <button
          type="button"
          onClick={() => onChange(Math.min(max, value + step))}
          className="flex h-full w-8 items-center justify-center bg-gray-50 text-gray-500 hover:bg-gray-100 hover:text-gray-700 active:bg-gray-200 transition-colors"
        >
          <Plus className="h-3.5 w-3.5" />
        </button>
      </div>
    </div>
  )
}

// ─── 规格表格（含筛选）────────────────────────────────────────────────────────

function ProductTable({
  products,
  selectedSku,
  onSelect,
}: {
  products: StoreProduct[]
  selectedSku: string | null
  onSelect: (sku: string) => void
}) {
  const [filterVcpu, setFilterVcpu] = useState<string>("")
  const [filterMemory, setFilterMemory] = useState<string>("")
  const [filterName, setFilterName] = useState<string>("")

  const vcpuOptions = Array.from(new Set(products.map((p) => p.vcpu).filter((v) => v != null))).sort((a, b) => a! - b!) as number[]
  const memoryOptions = Array.from(new Set(products.map((p) => p.memory).filter(Boolean))).sort() as string[]

  const filtered = products
    .filter((p) => {
      if (filterVcpu && String(p.vcpu) !== filterVcpu) return false
      if (filterMemory && p.memory !== filterMemory) return false
      if (filterName && !p.name.toLowerCase().includes(filterName.toLowerCase())) return false
      return true
    })
  const sortedFiltered = sortStoreProducts(filtered)

  return (
    <div className="space-y-4">
      {/* 筛选栏 */}
      <div className="flex flex-wrap items-center gap-3">
        <span className="text-xs font-medium text-gray-500 shrink-0">筛选规格：</span>
        <select
          value={filterVcpu}
          onChange={(e) => setFilterVcpu(e.target.value)}
          className="h-8 rounded-lg border border-gray-200 bg-white px-3 text-sm text-gray-600 focus:border-sky-400 focus:outline-none focus:ring-1 focus:ring-sky-400"
        >
          <option value="">请选择 CPU</option>
          {vcpuOptions.map((v) => (
            <option key={v} value={String(v)}>{v} 核</option>
          ))}
        </select>
        <select
          value={filterMemory}
          onChange={(e) => setFilterMemory(e.target.value)}
          className="h-8 rounded-lg border border-gray-200 bg-white px-3 text-sm text-gray-600 focus:border-sky-400 focus:outline-none focus:ring-1 focus:ring-sky-400"
        >
          <option value="">请选择内存</option>
          {memoryOptions.map((m) => (
            <option key={m} value={m}>{m}</option>
          ))}
        </select>
        <input
          type="text"
          placeholder="规格名称"
          value={filterName}
          onChange={(e) => setFilterName(e.target.value)}
          className="h-8 w-40 rounded-lg border border-gray-200 bg-white px-3 text-sm text-gray-700 placeholder:text-gray-400 focus:border-sky-400 focus:outline-none focus:ring-1 focus:ring-sky-400"
        />
        {(filterVcpu || filterMemory || filterName) && (
          <button
            type="button"
            onClick={() => { setFilterVcpu(""); setFilterMemory(""); setFilterName("") }}
            className="text-xs text-gray-400 hover:text-gray-600 transition-colors"
          >
            清除
          </button>
        )}
      </div>

      {/* 表格 */}
      <div className="overflow-x-auto">
        <table className="w-full text-sm">
          <thead>
            <tr className="border-b border-gray-100 text-left text-xs font-medium text-gray-400">
              <th className="pb-3 pr-4 w-6"></th>
              <th className="pb-3 pr-4">规格名称</th>
              <th className="pb-3 pr-4">vCPU</th>
              <th className="pb-3 pr-4">内存</th>
              <th className="pb-3 pr-4">处理器型号</th>
              <th className="pb-3 pr-4">主频 / 睿频</th>
              <th className="pb-3 pr-4">上行速率</th>
              <th className="pb-3 pr-4">下行速率</th>
              <th className="pb-3 text-right">价格预估</th>
            </tr>
          </thead>
          <tbody className="divide-y divide-gray-50">
            {filtered.length === 0 ? (
              <tr>
                <td colSpan={9} className="py-8 text-center text-sm text-gray-400">无匹配规格</td>
              </tr>
            ) : sortedFiltered.map((p) => {
              const bw = parseBandwidth(p.bandwidth)
              const mp = minPricing(p)
              const isSelected = p.sku === selectedSku
              const soldOut = isOutOfStock(p)
              return (
                <tr
                  key={p.sku}
                  onClick={() => {
                    if (!soldOut) onSelect(p.sku)
                  }}
                  className={`transition-colors ${
                    soldOut
                      ? "cursor-not-allowed bg-gray-50/60 opacity-60"
                      : isSelected
                        ? "cursor-pointer bg-sky-50"
                        : "cursor-pointer hover:bg-gray-50"
                  }`}
                >
                  <td className="py-3 pr-3">
                    <div className={`h-4 w-4 rounded-full border-2 transition-colors flex items-center justify-center ${
                      isSelected ? "border-sky-500 bg-sky-500" : "border-gray-300 bg-white"
                    }`}>
                      {isSelected && <div className="h-1.5 w-1.5 rounded-full bg-white" />}
                    </div>
                  </td>
                  <td className="py-3 pr-4">
                    <div className="flex items-center gap-2">
                      <span className={`font-medium ${isSelected ? "text-sky-700" : "text-gray-800"}`}>{p.name}</span>
                      {p.is_featured && (
                        <span className="inline-flex items-center gap-0.5 rounded-full bg-amber-50 px-1.5 py-0.5 text-[10px] font-medium text-amber-600">
                          <Zap className="h-2.5 w-2.5" />推荐
                        </span>
                      )}
                      <span className={`inline-flex items-center rounded-full px-1.5 py-0.5 text-[10px] font-medium ${
                        soldOut
                          ? "bg-red-50 text-red-600"
                          : p.stock_policy === "tracked"
                            ? "bg-emerald-50 text-emerald-600"
                            : "bg-gray-100 text-gray-500"
                      }`}>
                        {stockLabel(p)}
                      </span>
                    </div>
                  </td>
                  <td className="py-3 pr-4 text-gray-600">{p.vcpu != null ? `${p.vcpu} 核` : "—"}</td>
                  <td className="py-3 pr-4 text-gray-600">{p.memory ?? "—"}</td>
                  <td className="py-3 pr-4 text-gray-500 text-xs">{p.cpu_model ?? "—"}</td>
                  <td className="py-3 pr-4 text-gray-500 text-xs">
                    {p.cpu_base_mhz != null
                      ? `${(p.cpu_base_mhz / 1000).toFixed(1)} GHz${p.cpu_turbo_mhz ? ` / ${(p.cpu_turbo_mhz / 1000).toFixed(1)} GHz` : ""}`
                      : "—"}
                  </td>
                  <td className="py-3 pr-4 text-gray-600">{bw.up != null ? `${bw.up} Mbps` : "—"}</td>
                  <td className="py-3 pr-4 text-gray-600">{bw.down != null ? `${bw.down} Mbps` : "—"}</td>
                  <td className="py-3 text-right">
                    {mp ? (
                      <span className="font-semibold text-sky-600">
                        ¥{mp.price.toFixed(2)}
                        <span className="text-xs font-normal text-gray-400">/{CYCLE_LABEL[mp.cycle] ?? mp.cycle}</span>
                      </span>
                    ) : (
                      <span className="text-gray-400">—</span>
                    )}
                  </td>
                </tr>
              )
            })}
          </tbody>
        </table>
      </div>
    </div>
  )
}

// ─── 子组件：分区卡片 ─────────────────────────────────────────────────────────

function SectionCard({ title, children }: { title: string; children: React.ReactNode }) {
  return (
    <div className="rounded-2xl border border-gray-200 bg-white shadow-sm">
      <div className="border-b border-gray-100 px-6 py-4">
        <div className="flex items-center gap-2.5">
          <div className="w-1 h-5 rounded-full" style={{ background: "linear-gradient(to bottom, #0ea5e9, #e0f2fe)" }} />
          <h3 className="font-semibold text-gray-800">{title}</h3>
        </div>
      </div>
      <div className="px-6 py-5">{children}</div>
    </div>
  )
}

function PluginPurchaseFieldRow({
  field,
  value,
  onChange,
}: {
  field: StoreProvisionPurchaseField
  value: unknown
  onChange: (value: unknown) => void
}) {
  const label = `${field.label}${field.required ? " *" : ""}`
  const baseClass = "w-48 rounded-lg border border-gray-200 bg-white px-3 text-sm text-gray-700 placeholder:text-gray-400 focus:border-sky-400 focus:outline-none focus:ring-1 focus:ring-sky-400"
  let control: React.ReactNode
  if (field.type === "textarea") {
    control = (
      <textarea
        value={String(value ?? "")}
        onChange={(event) => onChange(event.target.value)}
        placeholder={field.placeholder}
        className={`${baseClass} min-h-20 py-2`}
      />
    )
  } else if (field.type === "select") {
    control = (
      <select
        value={String(value ?? "")}
        onChange={(event) => onChange(event.target.value)}
        className={`h-9 ${baseClass}`}
      >
        <option value="">请选择</option>
        {(field.options ?? []).map((option) => (
          <option key={option.value} value={option.value}>{option.label}</option>
        ))}
      </select>
    )
  } else if (field.type === "checkbox") {
    control = (
      <input
        type="checkbox"
        checked={Boolean(value)}
        onChange={(event) => onChange(event.target.checked)}
        className="h-4 w-4 rounded border-gray-300 text-sky-500 focus:ring-sky-400"
      />
    )
  } else {
    control = (
      <input
        type={field.type === "number" ? "number" : "text"}
        value={String(value ?? "")}
        onChange={(event) => onChange(event.target.value)}
        placeholder={field.placeholder}
        className={`h-9 ${baseClass}`}
      />
    )
  }

  return (
    <div className="flex items-start justify-between gap-4">
      <span className="text-sm text-gray-600 shrink-0 pt-2">{label}</span>
      {control}
    </div>
  )
}

function PromoRecommendBadge({ label }: { label: string }) {
  return (
    <span
      aria-label={label}
      className="pointer-events-none absolute -right-1 -top-2 z-10 bg-gradient-to-r from-red-600 to-orange-500 px-2.5 py-1 text-[11px] font-semibold leading-none text-white shadow-[0_6px_14px_rgba(220,38,38,0.2)]"
      role="img"
      style={{ clipPath: "polygon(8px 0, 100% 0, calc(100% - 8px) 100%, 0 100%)" }}
    >
      {label}
    </span>
  )
}

function tooltipMinWidth(text: string) {
  const chars = Array.from(text.trim()).length
  return `${Math.min(Math.max(chars, 8), 24)}em`
}

// ─── Hero 区 ──────────────────────────────────────────────────────────────────

function HeroSection({ groupName, onBack }: { groupName: string; onBack: () => void }) {
  return (
    <section
      className="relative w-full overflow-hidden"
      style={{
        backgroundImage: `url('${STORE_HERO_IMAGE}')`,
        backgroundSize: "cover",
        backgroundPosition: "center",
      }}
    >
      <button
        type="button"
        onClick={onBack}
        className="absolute left-6 top-6 inline-flex items-center gap-1.5 rounded-md border border-white/70 bg-white/75 px-3 py-1.5 text-sm font-medium text-gray-700 shadow-sm backdrop-blur transition-colors hover:border-sky-200 hover:text-sky-600"
      >
        <ArrowLeft className="h-4 w-4" />
        返回
      </button>
      <div className="px-6 py-14 text-center">
        <h2 className="text-3xl font-bold text-gray-900 tracking-wide">ECS 弹性云服务器</h2>
        {groupName && (
          <p className="mt-1 text-sm text-gray-600">{groupName}</p>
        )}
        <p className="mt-4 text-sm leading-relaxed text-gray-700 max-w-2xl mx-auto">
          提供安全可靠的弹性计算服务。您可以实时升级计算资源，适应变化的业务需求，并只需按实际使用的资源计费。<br />
          稳定、安全、弹性、高性能的云端计算服务，实时满足您的多样性业务需求 ECS（Elastic Compute Service）
        </p>
      </div>
    </section>
  )
}

// ─── 主组件 ───────────────────────────────────────────────────────────────────

export default function StoreProducts() {
  const { categorySlug, groupSlug } = useParams<{ categorySlug: string; groupSlug: string }>()
  const navigate = useNavigate()
	const [searchParams] = useSearchParams()
  const { user } = useAuth()
	const requestedSku = searchParams.get("sku")

  const [groups, setGroups] = useState<StoreGroup[]>([])
  const [categories, setCategories] = useState<StoreCategory[]>([])
  // 所有 category 的第一个 group slug，用于区域跳转时直接定位，避免经过 StoreGroupList
  const [catFirstGroup, setCatFirstGroup] = useState<Record<string, string>>({})
  const [products, setProducts] = useState<StoreProduct[]>([])
  const [initialLoading, setInitialLoading] = useState(true)
  const [productsLoading, setProductsLoading] = useState(false)
  const hasLoadedOnce = useRef(false)

  // 选中状态
  const [selectedSku, setSelectedSku] = useState<string | null>(null)
  const [selectedCycle, setSelectedCycle] = useState<string>("monthly")
  const [selectedOs, setSelectedOs] = useState<string | null>(null) // stores os value (ID)
  const [selectedOsLabel, setSelectedOsLabel] = useState<string | null>(null)
  const [sliderValues, setSliderValues] = useState<Record<string, number>>({})
  const [pluginFieldValues, setPluginFieldValues] = useState<Record<string, unknown>>({})
  const [autoRenew, setAutoRenew] = useState(false)
  const [alias, setAlias] = useState("")
  const [quantity, setQuantity] = useState(1)

  const osSectionRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    if (!("serviceWorker" in navigator)) return
    navigator.serviceWorker.ready
      .then((registration) => {
        registration.active?.postMessage({ type: "PRECACHE_STORE_HERO" })
      })
      .catch(() => {
        // Image cache warm-up is optional.
      })
  }, [])

  useEffect(() => {
    if (!categorySlug || !groupSlug) return
    if (!hasLoadedOnce.current) {
      setInitialLoading(true)
    } else {
      setProductsLoading(true)
    }
    Promise.all([fetchCategories(), fetchGroups(categorySlug), fetchProducts(categorySlug, groupSlug)])
      .then(([catRes, grpRes, prodRes]) => {
        const cats = catRes.data ?? []
        setCategories(cats)
        setGroups(grpRes.data ?? [])
        const prods = prodRes.data ?? []
        setProducts(prods)
        const sortedProducts = sortStoreProducts(prods)
		const requestedProduct = requestedSku ? sortedProducts.find((product) => product.sku === requestedSku) : null
        const firstProd =
		  requestedProduct
		  ?? sortedProducts.find((p) => p.api_type !== "plugin" && !isOutOfStock(p))
          ?? sortedProducts.find((p) => p.api_type !== "plugin")
          ?? sortedProducts.find((p) => !isOutOfStock(p))
          ?? sortedProducts[0]
          ?? null
        setSelectedSku(firstProd?.sku ?? null)
        setSliderValues(defaultSliderValues(firstProd))
        setPluginFieldValues(defaultPluginFieldValues(firstProd))
        setQuantity(firstProd ? productMinQuantity(firstProd) : 1)
        // 预取所有其他 category 的第一个 group，后台静默完成
        const otherCats = cats.filter((c) => c.slug !== categorySlug)
        Promise.all(otherCats.map((c) => fetchGroups(c.slug).then((r) => ({ slug: c.slug, first: r.data?.[0]?.slug }))))
          .then((results) => {
            const map: Record<string, string> = { [categorySlug]: grpRes.data?.[0]?.slug ?? groupSlug }
            for (const r of results) if (r.first) map[r.slug] = r.first
            setCatFirstGroup(map)
          })
      })
      .finally(() => {
        hasLoadedOnce.current = true
        setInitialLoading(false)
        setProductsLoading(false)
      })
  }, [categorySlug, groupSlug, requestedSku])

  const selectedProduct = useMemo(
    () => products.find((p) => p.sku === selectedSku) ?? null,
    [products, selectedSku]
  )

  // 保留上一次有效的 product，切换加载期间不让下方卡片塌陷
  const lastProductRef = useRef<StoreProduct | null>(null)
  if (selectedProduct) lastProductRef.current = selectedProduct
  const displayProduct = selectedProduct ?? (productsLoading ? lastProductRef.current : null)

  useEffect(() => {
    if (!selectedProduct) return
    setQuantity((q) => clampProductQuantity(selectedProduct, q))
  }, [selectedProduct])

  // 切换产品时重置 slider
  const selectProduct = (sku: string) => {
    const p = products.find((x) => x.sku === sku)
    if (!p) return
    if (isOutOfStock(p)) {
      toast.error("该规格已售罄")
      return
    }
    setSelectedSku(sku)
    setSliderValues(defaultSliderValues(p))
    setPluginFieldValues(defaultPluginFieldValues(p))
    setQuantity((q) => clampProductQuantity(p, q))
    setSelectedOs(null)
    setSelectedOsLabel(null)
  }
  const currentPricing = useMemo(() => {
    if (!displayProduct) return null
    return (
      displayProduct.pricings.find((p) => p.is_enabled && p.cycle === selectedCycle) ??
      displayProduct.pricings.find((p) => p.is_enabled) ??
      null
    )
  }, [displayProduct, selectedCycle])

  // slider 附加总费用
  const sliderTotal = useMemo(() => {
    if (!displayProduct) return 0
    let total = 0
    for (const f of displayProduct.provision_config ?? []) {
      if (f.type !== "slider") continue
      const key = f.def.split("|")[0].trim()
      const val = sliderValues[key] ?? f.slider_min ?? 0
      total += sliderExtra(f, val)
    }
    return total
  }, [displayProduct, sliderValues])

  const totalPrice = ((currentPricing?.price ?? 0) + sliderTotal) * quantity
  const setupFee = currentPricing?.setup_fee ?? 0
  const selectedSoldOut = isOutOfStock(displayProduct)
  const maxPurchasable = displayProduct ? productMaxQuantity(displayProduct) : 0
  const quantityExceedsLimit = !!displayProduct && !selectedSoldOut && maxPurchasable > 0 && quantity > maxPurchasable

  const [buying, setBuying] = useState(false)

  const handleBuy = async () => {
    if (!displayProduct || !currentPricing) return
    const isPlugin = isPluginProvisionProduct(displayProduct)
    if (!isPlugin && !selectedOs) return
    if (isOutOfStock(displayProduct)) {
      toast.error("该规格已售罄")
      return
    }
    const max = productMaxQuantity(displayProduct)
    if (max > 0 && quantity > max) {
      toast.error(`购买数量超过可用库存，当前最多可购买 ${max} 台`)
      return
    }
    if (!user) {
      navigate("/login")
      return
    }
    const missingField = pluginPurchaseFields(displayProduct).find(
      (field) => field.required && isPluginFieldEmpty(pluginFieldValues[field.key]),
    )
    if (isPlugin && missingField) {
      toast.error(`请填写${missingField.label}`)
      return
    }
    setBuying(true)
    try {
      const nextSliderValues = isPlugin
        ? { ...sliderValues, __plugin_fields: pluginFieldValues }
        : sliderValues
      const res = await addCartItem({
        product_id: displayProduct.id,
        cycle: selectedCycle,
        quantity,
        auto_renew: autoRenew,
        alias: alias || null,
        os_image: isPlugin ? null : `${selectedOs}|${selectedOsLabel ?? selectedOs}`,
        unit_price: currentPricing.price,
        addon_price: sliderTotal,
        setup_fee: currentPricing.setup_fee,
        slider_values: nextSliderValues,
      })
      toast.success("已加入购物车")
      const newItemId = res.data?.id
      navigate(newItemId ? `/cart?from=store&highlight=${newItemId}` : "/cart")
    } catch (e: unknown) {
      const detail = (e as { response?: { data?: { detail?: string } } })?.response?.data?.detail
      toast.error(detail ?? "加入购物车失败")
    } finally {
      setBuying(false)
    }
  }

  const currentGroup = useMemo(
    () => groups.find((g) => g.slug === groupSlug) ?? null,
    [groups, groupSlug],
  )
  const currentOsOptions = useMemo<StoreOsOption[]>(() => {
    const productOptions = productOsOptions(displayProduct)
    return productOptions.length > 0 ? productOptions : currentGroup?.os_options ?? []
  }, [currentGroup, displayProduct])
  const hasOsOptions = currentOsOptions.length > 0
  const isPluginProduct = isPluginProvisionProduct(displayProduct)
  const requiresOs = !!displayProduct && !isPluginProduct
  const osUnavailable = requiresOs && !hasOsOptions
  const osMissing = requiresOs && !selectedOs

  useEffect(() => {
    if (!selectedOs) return
    const stillAvailable = currentOsOptions.some((option) => String(option.value) === selectedOs)
    if (!stillAvailable) {
      setSelectedOs(null)
      setSelectedOsLabel(null)
    }
  }, [currentOsOptions, selectedOs])

  if (initialLoading) {
    return (
      <div className="min-h-screen bg-white">
        <div className="h-48 animate-pulse bg-gray-100" />
        <div className="mx-auto max-w-7xl px-6 py-6 space-y-5">
          <div className="h-4 w-48 rounded bg-gray-100 animate-pulse" />
          <div className="rounded-2xl border border-gray-200 bg-white shadow-sm p-6 space-y-3 animate-pulse">
            <div className="h-4 w-24 rounded bg-gray-100" />
            <div className="flex gap-3">
              {[...Array(3)].map((_, i) => <div key={i} className="h-12 w-32 rounded bg-gray-100" />)}
            </div>
            <div className="flex gap-2 pt-3">
              {[...Array(2)].map((_, i) => <div key={i} className="h-9 w-28 rounded bg-gray-100" />)}
            </div>
          </div>
          <div className="rounded-2xl border border-gray-200 bg-white shadow-sm p-6 space-y-3 animate-pulse">
            <div className="h-4 w-20 rounded bg-gray-100" />
            {[...Array(4)].map((_, i) => (
              <div key={i} className="flex gap-4 py-3 border-b border-gray-50 last:border-0">
                <div className="h-4 w-32 rounded bg-gray-100" />
                <div className="h-4 w-16 rounded bg-gray-100" />
                <div className="h-4 w-16 rounded bg-gray-100" />
                <div className="h-4 w-28 rounded bg-gray-100" />
                <div className="ml-auto h-4 w-20 rounded bg-gray-100" />
              </div>
            ))}
          </div>
        </div>
      </div>
    )
  }

  // 从 "CN|国内云" 解析出 { code: "CN", label: "国内云" }
  function parseCatName(name: string): { code: string; label: string } {
    const idx = name.indexOf("|")
    if (idx === -1) return { code: "", label: name }
    return { code: name.slice(0, idx).toUpperCase(), label: name.slice(idx + 1) }
  }

  const FLAG_MAP: Record<string, string> = {
    CN: "/national/中国国旗.svg",
    HK: "/national/香港.svg",
    US: "/national/美国国旗.svg",
    JP: "/national/日本国旗.svg",
  }
  function getFlagSrc(code: string): string {
    return FLAG_MAP[code] ?? "/national/联合国.svg"
  }

  // 当前 category 对应的区域信息
  const currentCatParsed = categories.length > 0
    ? parseCatName(categories.find((c) => c.slug === categorySlug)?.name ?? "")
    : null

  return (
    <div className="min-h-screen bg-white">
      <HeroSection groupName={currentGroup?.name ?? ""} onBack={() => navigate(-1)} />

      <div className="mx-auto max-w-7xl px-6 py-6">

        {/* 面包屑 */}
        <div className="mb-5 flex items-center gap-1.5 text-sm text-gray-400">
          <Link to={`/store/${categorySlug}`} className="hover:text-gray-600 transition-colors">
            购买服务器
          </Link>
          <ChevronRight className="h-3.5 w-3.5" />
          {currentCatParsed && (
            <>
              <span className="text-gray-500">{currentCatParsed.label}</span>
              <ChevronRight className="h-3.5 w-3.5" />
            </>
          )}
          <span className="text-gray-700 font-medium">{currentGroup?.name ?? groupSlug}</span>
        </div>

        {/* 主体：左侧内容 + 右侧价格计算器 */}
        <div className="flex gap-6 items-start">

          {/* 左侧内容区 */}
          <div className="flex-1 min-w-0 space-y-5">

            {/* ① 选择区域 + 线路 */}
            {categories.length > 0 && (
              <SectionCard title="选择区域">
                <div className="flex flex-wrap gap-3">
                  {categories.map((cat) => {
                    const { code, label } = parseCatName(cat.name)
                    const isActive = cat.slug === categorySlug
                    return (
                      <button
                        key={cat.id}
                        type="button"
                        onClick={() => {
                          const first = catFirstGroup[cat.slug]
                          if (first) navigate(`/store/${cat.slug}/${first}`)
                          else navigate(`/store/${cat.slug}`)
                        }}
                        className={`group relative flex min-h-12 items-center gap-2.5 border py-3 text-sm font-medium transition-all ${
                          cat.is_featured ? "pl-4 pr-12" : "pl-4 pr-4"
                        } ${
                          isActive
                            ? "bg-sky-50 text-sky-700 border-sky-400 shadow-sm"
                            : "bg-white text-gray-600 border-gray-200 hover:border-sky-300 hover:text-sky-600"
                        }`}
                      >
                        {cat.is_featured && (
                          <PromoRecommendBadge label={cat.featured_label} />
                        )}
                        <img src={getFlagSrc(code)} alt={code} className="h-5 w-7 object-cover rounded-sm shrink-0" />
                        <span>{label}</span>
                        {cat.description && (
                          <span
                            className="invisible pointer-events-none absolute left-1/2 top-full z-50 mt-2 block max-w-[min(28rem,calc(100vw-2rem))] -translate-x-1/2 translate-y-1 whitespace-normal bg-gray-900 px-3 py-2 text-left text-xs font-normal leading-relaxed text-white opacity-0 shadow-lg transition-all delay-0 duration-150 ease-out group-hover:visible group-hover:translate-y-0 group-hover:opacity-100 group-hover:delay-500"
                            style={{ minWidth: tooltipMinWidth(cat.description) }}
                          >
                            <span className="absolute -top-1 left-1/2 h-2 w-2 -translate-x-1/2 rotate-45 bg-gray-900" />
                            {cat.description}
                          </span>
                        )}
                      </button>
                    )
                  })}
                </div>
                {groups.length > 0 && (
                  <div className="flex flex-wrap gap-2 mt-4 pt-4 border-t border-gray-100">
                    {groups.map((g) => (
                      <button
                        key={g.id}
                        type="button"
                        onClick={() => navigate(`/store/${categorySlug}/${g.slug}`)}
                        className={`border px-4 py-2 text-sm font-medium transition-all ${
                          g.slug === groupSlug
                            ? "bg-sky-50 text-sky-700 border-sky-400"
                            : "bg-white text-gray-600 border-gray-200 hover:border-sky-300 hover:text-sky-600"
                        }`}
                      >
                        {g.name}
                      </button>
                    ))}
                  </div>
                )}
              </SectionCard>
            )}

            {/* ② 规格选择 */}
            <SectionCard title="选择规格">
              <div className={`transition-opacity duration-200 ${productsLoading ? "opacity-40 pointer-events-none" : "opacity-100"}`}>
                {products.length === 0 && !productsLoading ? (
                  <p className="text-sm text-gray-400">暂无在售产品</p>
                ) : (
                  <ProductTable
                    products={products}
                    selectedSku={selectedSku}
                    onSelect={selectProduct}
                  />
                )}
              </div>
            </SectionCard>

            <div className={`space-y-5 transition-opacity duration-200 ${productsLoading ? "opacity-40 pointer-events-none" : "opacity-100"}`}>
            {displayProduct && (
              <>
                {/* ③ 存储配置 */}
                {!isPluginProduct && <StorageSection product={displayProduct} sliderValues={sliderValues} setSliderValues={setSliderValues} />}
                {/* ④ 网络与安全 */}
                {!isPluginProduct && <NetworkSection product={displayProduct} sliderValues={sliderValues} setSliderValues={setSliderValues} />}
                {/* ⑤ 操作系统 */}
                {!isPluginProduct && <OsSection options={currentOsOptions} selectedOs={selectedOs} onSelect={(value, label) => { setSelectedOs(value); setSelectedOsLabel(label) }} sectionRef={osSectionRef} />}

                {/* ⑥ 购买设置 */}
                <SectionCard title="购买设置">
                  <div className="space-y-4">
                    {/* 自动续费 */}
                    <div className="flex items-center justify-between">
                      <div>
                        <span className="text-sm text-gray-600">自动续费</span>
                        {autoRenew && <span className="ml-2 text-xs text-sky-500">到期自动续费</span>}
                      </div>
                      <button
                        type="button"
                        role="switch"
                        aria-checked={autoRenew}
                        onClick={() => setAutoRenew(v => !v)}
                        className={`relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 focus:outline-none ${autoRenew ? "bg-sky-500" : "bg-gray-200"}`}
                      >
                        <span className={`pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow-sm transition-transform duration-200 ${autoRenew ? "translate-x-5" : "translate-x-0"}`} />
                      </button>
                    </div>

                    {/* 主机别名 */}
                    <div className="flex items-center justify-between gap-4">
                      <span className="text-sm text-gray-600 shrink-0">主机别名</span>
                      <input
                        type="text"
                        value={alias}
                        onChange={(e) => setAlias(e.target.value)}
                        placeholder="选填，方便识别"
                        className="h-9 w-48 rounded-lg border border-gray-200 bg-white px-3 text-sm text-gray-700 placeholder:text-gray-400 focus:border-sky-400 focus:outline-none focus:ring-1 focus:ring-sky-400"
                      />
                    </div>

                    {isPluginProduct && pluginPurchaseFields(displayProduct).map((field) => (
                      <PluginPurchaseFieldRow
                        key={field.key}
                        field={field}
                        value={pluginFieldValues[field.key]}
                        onChange={(value) => setPluginFieldValues((values) => ({ ...values, [field.key]: value }))}
                      />
                    ))}

                    {/* 购买数量 */}
                    <div className="flex items-center justify-between">
                      <span className="text-sm text-gray-600">购买数量</span>
                      <div className="flex items-center gap-3">
                        <button
                          type="button"
                          onClick={() => setQuantity(q => clampProductQuantity(displayProduct, q - 1))}
                          disabled={quantity <= productMinQuantity(displayProduct)}
                          className="h-8 w-8 rounded-lg border border-gray-200 flex items-center justify-center text-gray-500 hover:bg-gray-50 disabled:opacity-40"
                        ><Minus size={14} /></button>
                        <span className="text-sm font-medium text-gray-700 w-6 text-center">{quantity}</span>
                        <button
                          type="button"
                          onClick={() => setQuantity(q => clampProductQuantity(displayProduct, q + 1))}
                          disabled={selectedSoldOut || (maxPurchasable > 0 && quantity >= maxPurchasable)}
                          className="h-8 w-8 rounded-lg border border-gray-200 flex items-center justify-center text-gray-500 hover:bg-gray-50 disabled:opacity-40"
                        ><Plus size={14} /></button>
                        <span className="text-sm text-gray-400">台</span>
                      </div>
                    </div>
                  </div>
                </SectionCard>
              </>
            )}
            </div>
          </div>

          {/* 右侧价格预算清单 */}
          <div className="w-80 shrink-0 sticky top-24">
            <div className="border border-gray-200 bg-white shadow-sm overflow-hidden">
              <div className="border-b border-gray-200 px-5 py-3 bg-gray-50">
                <h3 className="text-sm font-semibold text-gray-800">价格预算清单</h3>
              </div>
              {displayProduct ? (
                <>
                  {/* 配置明细 */}
                  <div className="px-5 py-3 space-y-0 divide-y divide-gray-100">
                    {/* 数据中心 */}
                    {currentGroup && (
                      <BillRow label="数据中心" value={currentGroup.name} />
                    )}
                    {/* 实例类型 */}
                    <BillRow label="实例类型" value={displayProduct.name} />
                    <BillRow label="库存状态" value={stockLabel(displayProduct)} />
                    {/* 实例规格 */}
                    {(displayProduct.vcpu != null || displayProduct.memory) && (
                      <BillRow
                        label="实例规格"
                        value={[
                          displayProduct.vcpu != null ? `${displayProduct.vcpu}核心` : null,
                          displayProduct.memory ? displayProduct.memory : null,
                        ].filter(Boolean).join(" ")}
                      />
                    )}
                    {/* 系统盘 */}
                    {(() => {
                      const cfg = (displayProduct.provision_config ?? []).find(f => f.def.startsWith("system_disk_size"))
                      const val = cfg?.type === "slider"
                        ? sliderValues["system_disk_size"] ?? cfg.slider_min ?? 0
                        : cfg?.type === "fixed" ? cfg.value : null
                      if (val == null && !displayProduct.disk) return null
                      return <BillRow label="云系统盘" value={val != null ? `${val} GiB` : displayProduct.disk ?? "—"} />
                    })()}
                    {/* 数据盘 */}
                    {(() => {
                      const cfg = (displayProduct.provision_config ?? []).find(f => f.def.startsWith("data_disk_size"))
                      if (!cfg) return null
                      const val = cfg.type === "slider"
                        ? sliderValues["data_disk_size"] ?? cfg.slider_min ?? 0
                        : cfg.type === "fixed" ? cfg.value : null
                      return <BillRow label="云数据盘" value={val != null ? `${val} GiB` : "—"} />
                    })()}
                    {/* 带宽 */}
                    {(() => {
                      const bw = parseBandwidth(displayProduct.bandwidth)
                      if (bw.up == null && bw.down == null) return null
                      return (
                        <>
                          {bw.up != null && <BillRow label="公网带宽" value={`${bw.up} Mbps`} />}
                          {bw.down != null && <BillRow label="下行速率" value={`${bw.down} Mbps`} />}
                        </>
                      )
                    })()}
                    {/* 操作系统 */}
                    {selectedOs && (
                      <div className="flex items-start justify-between py-2 gap-2">
                        <span className="text-xs text-gray-400 shrink-0 pt-0.5">系统镜像</span>
                        <div className="flex items-center gap-1 min-w-0">
                          <OsIcon name={selectedOsLabel ?? selectedOs} size={13} />
                          <span className="text-xs text-gray-700 text-right break-all">{selectedOsLabel ?? selectedOs}</span>
                        </div>
                      </div>
                    )}
                    {/* 购买数量 */}
                    <BillRow label="购买数量" value={`${quantity} 台`} />
                    {/* 购买时长 */}
                    <div className="py-2">
                      <div className="flex items-center justify-between mb-1.5">
                        <span className="text-xs text-gray-400">购买时长</span>
                        <span className="text-xs text-gray-700 font-medium">{CYCLE_LABEL[selectedCycle] ?? selectedCycle}</span>
                      </div>
                      <select
                        value={selectedCycle}
                        onChange={(e) => setSelectedCycle(e.target.value)}
                        className="w-full h-8 border border-gray-200 bg-white px-2 text-xs text-gray-700 focus:border-sky-400 focus:outline-none focus:ring-1 focus:ring-sky-400"
                      >
                        {displayProduct.pricings
                          .filter((p) => p.is_enabled)
                          .sort((a, b) => a.sort_order - b.sort_order)
                          .map((p) => (
                            <option key={p.cycle} value={p.cycle}>
                              {CYCLE_LABEL[p.cycle] ?? p.cycle}（¥{p.price.toFixed(2)}）
                            </option>
                          ))}
                      </select>
                    </div>
                  </div>

                  {/* 费用总计 */}
                  <div className="border-t-2 border-gray-200 px-5 py-4 bg-gray-50">
                    <div className="flex items-baseline justify-between mb-1">
                      <span className="text-sm font-medium text-gray-600">费用总计：</span>
                      <div className="text-right">
                        <span className="text-2xl font-bold text-sky-600">¥{totalPrice.toFixed(2)}</span>
                      </div>
                    </div>
                    {currentPricing?.original_price != null && currentPricing.original_price > currentPricing.price && (
                      <div className="flex items-center justify-between mb-2">
                        <span className="text-xs text-gray-400">原价</span>
                        <span className="text-xs text-gray-400 line-through">¥{(currentPricing.original_price * quantity).toFixed(2)}</span>
                      </div>
                    )}
                    {sliderTotal > 0 && (
                      <div className="flex items-center justify-between mb-2">
                        <span className="text-xs text-gray-400">扩展配置</span>
                        <span className="text-xs text-gray-500">+¥{(sliderTotal * quantity).toFixed(2)}</span>
                      </div>
                    )}
                    {setupFee > 0 && (
                      <div className="flex items-center justify-between mb-2">
                        <span className="text-xs text-gray-400">安装费（一次性）</span>
                        <span className="text-xs text-gray-500">¥{setupFee.toFixed(2)}</span>
                      </div>
                    )}
                    <button
                      type="button"
                      disabled={buying || osUnavailable || selectedSoldOut || quantityExceedsLimit}
                      onClick={osUnavailable || selectedSoldOut || quantityExceedsLimit
                        ? undefined
                        : osMissing
                        ? () => osSectionRef.current?.scrollIntoView({ behavior: "smooth", block: "center" })
                        : handleBuy
                      }
                      className={`w-full py-2.5 text-sm font-semibold !text-white transition-opacity mt-3 [&_*]:!text-white ${
                        buying
                          ? "bg-sky-400 cursor-wait"
                          : osUnavailable || selectedSoldOut || quantityExceedsLimit
                            ? "bg-gray-300 cursor-not-allowed"
                          : osMissing
                            ? "bg-red-500 hover:bg-red-600 active:bg-red-700"
                            : "bg-sky-500 hover:bg-sky-600"
                      }`}
                    >
                      {buying
                        ? "加入中…"
                        : selectedSoldOut
                          ? "已售罄"
                          : quantityExceedsLimit
                            ? "库存不足"
                            : osUnavailable
                              ? "系统镜像未配置"
                              : osMissing
                                ? "请先选择操作系统 ↓"
                                : "立即购买"}
                    </button>
                    <p className="text-xs text-gray-400 text-center mt-2">参考价格，具体扣费请以账单为准</p>
                  </div>
                </>
              ) : (
                <p className="text-sm text-gray-400 py-8 text-center">请先选择规格</p>
              )}
            </div>
          </div>

        </div>
      </div>
    </div>
  )
}

// ─── 存储配置分区 ─────────────────────────────────────────────────────────────

function StorageSliderField({
  field,
  value,
  onChange,
}: {
  field: StoreConfigField
  value: number
  onChange: (v: number) => void
}) {
  const min = field.slider_min ?? 0
  const max = field.slider_max ?? 100
  const step = field.slider_step ?? 1
  const unit = field.slider_unit ?? ""
  const label = field.def.includes("|") ? field.def.split("|")[1] : field.def
  const precision = Math.max(decimalPlaces(step), decimalPlaces(min), decimalPlaces(max))

  const commitValue = (next: number | string | null) => {
    if (next === null || next === "") return
    const numeric = typeof next === "number" ? next : Number(next)
    if (!Number.isFinite(numeric)) return
    const clamped = Math.min(max, Math.max(min, numeric))
    onChange(Number(clamped.toFixed(precision)))
  }

  return (
    <Row gutter={16} align="middle">
      <Col flex="96px">
        <AntText strong>{label}</AntText>
      </Col>
      <Col flex="auto">
        <AntSlider
          min={min}
          max={max}
          step={step}
          value={value}
          onChange={(next) => {
            if (typeof next === "number") onChange(next)
          }}
          tooltip={{ formatter: (next) => `${next ?? value} ${unit}` }}
        />
      </Col>
      <Col flex="132px">
        <InputNumber
          min={min}
          max={max}
          step={step || 1}
          precision={precision}
          value={value}
          onChange={commitValue}
          addonAfter={unit || undefined}
          controls
          keyboard
          aria-label={`${label}精确值`}
          style={{ width: "100%" }}
        />
      </Col>
    </Row>
  )
}

function StorageValueRow({ label, value }: { label: string; value: React.ReactNode }) {
  return (
    <Row gutter={16} align="middle">
      <Col flex="96px">
        <AntText strong>{label}</AntText>
      </Col>
      <Col flex="auto">
        <AntText>{value}</AntText>
      </Col>
    </Row>
  )
}

function StorageSection({
  product,
  sliderValues,
  setSliderValues,
}: {
  product: StoreProduct
  sliderValues: Record<string, number>
  setSliderValues: React.Dispatch<React.SetStateAction<Record<string, number>>>
}) {
  const config = product.provision_config ?? []
  const sysDisk = findConfig(config, "system_disk_size")
  const dataDisk = findConfig(config, "data_disk_size")

  // 固定值展示
  const sysDiskFixed = sysDisk?.type === "fixed" ? sysDisk.value : null
  const dataDiskFixed = dataDisk?.type === "fixed" ? dataDisk.value : null

  // 从 disk 字段兜底
  const diskFallback = product.disk

  const hasStorage = sysDisk || dataDisk || diskFallback

  if (!hasStorage) return null

  return (
    <SectionCard title="存储配置">
      <div className="space-y-5">
        {/* 系统盘 */}
        {sysDisk?.type === "slider" ? (
          <StorageSliderField
            field={sysDisk}
            value={sliderValues["system_disk_size"] ?? sysDisk.slider_min ?? 0}
            onChange={(v) => setSliderValues((prev) => ({ ...prev, system_disk_size: v }))}
          />
        ) : (
          <StorageValueRow
            label="系统盘"
            value={sysDiskFixed != null ? `${sysDiskFixed} GB` : diskFallback ?? "—"}
          />
        )}

        {/* 数据盘 */}
        {dataDisk?.type === "slider" ? (
          <StorageSliderField
            field={dataDisk}
            value={sliderValues["data_disk_size"] ?? dataDisk.slider_min ?? 0}
            onChange={(v) => setSliderValues((prev) => ({ ...prev, data_disk_size: v }))}
          />
        ) : dataDisk ? (
          <StorageValueRow
            label="数据盘"
            value={dataDiskFixed != null ? `${dataDiskFixed} GB` : "—"}
          />
        ) : null}
      </div>
    </SectionCard>
  )
}

// ─── 操作系统分区 ─────────────────────────────────────────────────────────────

function OsIcon({ name, size = 20, active = false }: { name: string; size?: number; active?: boolean }) {
  const src = osLogoOrNull(name)
  if (!src) return (
    <div
      style={{ width: size, height: size, fontSize: size * 0.5 }}
      className={`rounded-full flex items-center justify-center font-bold shrink-0 transition-all duration-200 ${
        active ? "bg-sky-50 qycw-auth-text-primary ring-1 ring-sky-100" : "bg-gray-100 text-gray-400"
      }`}
    >
      {name.charAt(0).toUpperCase()}
    </div>
  )
  return (
    <img
      src={src}
      alt={name}
      width={size}
      height={size}
      className={`shrink-0 object-contain transition-all duration-200 ${
        active ? "opacity-100 saturate-100" : "opacity-55 grayscale"
      }`}
    />
  )
}

// 从 label 提取发行版名称（取第一个单词）
function getDistro(label: string): string {
  const lower = label.toLowerCase()
  if (lower.includes("ubuntu")) return "Ubuntu"
  if (lower.includes("centos")) return "CentOS"
  if (lower.includes("debian")) return "Debian"
  if (lower.includes("almalinux") || lower.includes("alma linux")) return "AlmaLinux"
  if (lower.includes("rocky")) return "Rocky Linux"
  if (lower.includes("fedora")) return "Fedora"
  if (lower.includes("arch")) return "Arch Linux"
  if (lower.includes("alpine")) return "Alpine"
  if (lower.includes("amazon")) return "Amazon Linux"
  if (lower.includes("oracle")) return "Oracle Linux"
  if (lower.includes("red hat") || lower.includes("rhel")) return "Red Hat"
  if (lower.includes("opensuse") || lower.includes("open suse")) return "openSUSE"
  if (lower.includes("suse")) return "SUSE"
  if (lower.includes("openeuler")) return "openEuler"
  if (lower.includes("deepin")) return "Deepin"
  if (lower.includes("kali")) return "Kali"
  if (lower.includes("manjaro")) return "Manjaro"
  if (lower.includes("mint")) return "Linux Mint"
  if (lower.includes("nixos")) return "NixOS"
  if (lower.includes("gentoo")) return "Gentoo"
  if (lower.includes("freebsd")) return "FreeBSD"
  return label.split(" ")[0]
}

function OsSection({
  options,
  selectedOs,
  onSelect,
  sectionRef,
}: {
  options: StoreOsOption[]
  selectedOs: string | null
  onSelect: (value: string, label: string) => void
  sectionRef?: React.RefObject<HTMLDivElement | null>
}) {
  const windows = useMemo(
    () => options.filter((o) => o.label.toLowerCase().includes("windows")),
    [options],
  )
  const linux = useMemo(
    () => options.filter((o) => !o.label.toLowerCase().includes("windows")),
    [options],
  )

  // Linux 按发行版分组
  const linuxGroups = useMemo(() => linux.reduce<Record<string, typeof linux>>((acc, o) => {
    const distro = getDistro(o.label)
    if (!acc[distro]) acc[distro] = []
    acc[distro].push(o)
    return acc
  }, {}), [linux])
  const distroNames = useMemo(() => Object.keys(linuxGroups).sort(), [linuxGroups])

  const [osType, setOsType] = useState<"linux" | "windows">(linux.length > 0 ? "linux" : "windows")
  const [selectedDistro, setSelectedDistro] = useState<string | null>(distroNames[0] ?? null)
  const [showAll, setShowAll] = useState(false)
  const distroKey = distroNames.join("|")

  useEffect(() => {
    if (!options.length) return
    setOsType((current) => {
      if (current === "windows" && windows.length > 0) return "windows"
      return linux.length > 0 ? "linux" : "windows"
    })
    setSelectedDistro((current) => {
      if (current && linuxGroups[current]?.length) return current
      return distroNames[0] ?? null
    })
    setShowAll(false)
  }, [options.length, windows.length, linux.length, distroKey, distroNames, linuxGroups])

  const PAGE_SIZE = 10

  const allOptions = osType === "windows"
    ? windows
    : selectedDistro ? (linuxGroups[selectedDistro] ?? []) : []
  const visibleOptions = showAll ? allOptions : allOptions.slice(0, PAGE_SIZE)

  if (!options.length) {
    return (
      <div ref={sectionRef}>
        <SectionCard title="操作系统">
          <div className="rounded-lg border border-amber-200 bg-amber-50 px-4 py-3">
            <div className="text-sm font-medium text-amber-800">系统镜像未配置</div>
            <div className="mt-1 text-xs leading-relaxed text-amber-700">
              当前产品组暂未配置可选系统镜像，暂不能下单。
            </div>
          </div>
        </SectionCard>
      </div>
    )
  }

  return (
    <div ref={sectionRef}>
      <SectionCard title="操作系统">
        <div className="space-y-3">
        <div className="flex h-72 gap-4 overflow-hidden">
          <div className="flex w-32 shrink-0 flex-col gap-2">
            {linux.length > 0 && (
              <button
                type="button"
                onClick={() => { setOsType("linux"); setSelectedDistro(distroNames[0] ?? null); setShowAll(false) }}
                className={`flex items-center gap-2 rounded-lg border px-3 py-2 text-sm font-medium transition-all ${
                  osType === "linux"
                    ? "border-[#91caff] bg-[#e6f4ff] text-[#1677ff]"
                    : "border-transparent text-[#595959] hover:bg-[#f5f5f5]"
                }`}
              >
                <OsIcon name="linux" size={20} active={osType === "linux"} />
                Linux
              </button>
            )}
            {windows.length > 0 && (
              <button
                type="button"
                onClick={() => { setOsType("windows"); setSelectedDistro(null); setShowAll(false) }}
                className={`flex items-center gap-2 rounded-lg border px-3 py-2 text-sm font-medium transition-all ${
                  osType === "windows"
                    ? "border-[#91caff] bg-[#e6f4ff] text-[#1677ff]"
                    : "border-transparent text-[#595959] hover:bg-[#f5f5f5]"
                }`}
              >
                <OsIcon name="windows" size={20} active={osType === "windows"} />
                Windows
              </button>
            )}
          </div>

          <div className="w-px shrink-0 bg-[#f0f0f0]" />

          {osType === "linux" && distroNames.length > 0 && (
            <>
            <div className="flex w-36 shrink-0 flex-col gap-2 overflow-y-auto">
              {distroNames.map((distro) => {
                const active = selectedDistro === distro
                return (
                  <button
                    key={distro}
                    type="button"
                    onClick={() => { setSelectedDistro(distro); setShowAll(false) }}
                    className={`flex items-center gap-2 rounded-lg border px-3 py-2 text-sm font-medium transition-all ${
                      active
                        ? "border-[#91caff] bg-[#e6f4ff] text-[#1677ff]"
                        : "border-transparent text-[#595959] hover:bg-[#f5f5f5]"
                    }`}
                  >
                    <OsIcon name={distro} size={18} active={active} />
                    <span className="truncate">{distro}</span>
                  </button>
                )
              })}
            </div>
            <div className="w-px shrink-0 bg-[#f0f0f0]" />
            </>
          )}

          <div className="flex min-w-0 flex-1 flex-col gap-2 overflow-y-auto pr-1">
            {visibleOptions.map((o) => {
              const isSelected = selectedOs === String(o.value)
              return (
                <button
                  key={o.value}
                  type="button"
                  onClick={() => onSelect(String(o.value), o.label)}
                  className={`flex items-center justify-between gap-3 rounded-lg border px-3 py-2 text-left text-sm transition-all ${
                    isSelected
                      ? "border-[#91caff] bg-[#e6f4ff] text-[#1677ff] shadow-sm"
                      : "border-transparent text-[#595959] hover:bg-[#f5f5f5]"
                  }`}
                >
                  <span className="flex min-w-0 items-center gap-2">
                    <OsIcon name={o.label} size={18} active={isSelected} />
                    <span className="truncate">{o.label}</span>
                  </span>
                  {isSelected && <CheckCircle2 className="h-4 w-4 shrink-0" />}
                </button>
              )
            })}
            {allOptions.length > PAGE_SIZE && (
              <button
                type="button"
                onClick={() => setShowAll(v => !v)}
                className="flex w-full items-center gap-2 rounded-lg border border-transparent px-3 py-2 text-left text-sm font-medium text-[#595959] transition-all hover:bg-[#f5f5f5]"
              >
                {showAll ? "收起" : `显示更多（${allOptions.length - PAGE_SIZE} 个）`}
              </button>
            )}
          </div>
        </div>
        </div>
      </SectionCard>
    </div>
  )
}

// ─── 网络与安全分区 ───────────────────────────────────────────────────────────

function NetworkSection({
  product,
  sliderValues,
  setSliderValues,
}: {
  product: StoreProduct
  sliderValues: Record<string, number>
  setSliderValues: React.Dispatch<React.SetStateAction<Record<string, number>>>
}) {
  const config = product.provision_config ?? []
  const ipField = findConfig(config, "ip_num")
  const inBwField = findConfig(config, "in_bw")
  const outBwField = findConfig(config, "out_bw")

  const ipCount = ipField?.type === "fixed" ? Number(ipField.value ?? 0) : null
  const isNat = ipCount === 0 || ipCount === null

  const bw = parseBandwidth(product.bandwidth)
  const inBwFixed = inBwField?.type === "fixed" ? Number(inBwField.value) : bw.up
  const outBwFixed = outBwField?.type === "fixed" ? Number(outBwField.value) : bw.down

  return (
    <SectionCard title="网络与安全">
      <div className="space-y-5">
        {/* IP */}
        <div className="flex items-center justify-between">
          <span className="text-sm font-medium text-gray-700">IP 类型</span>
          <div className="text-right">
            {isNat ? (
              <span className="inline-flex items-center gap-1 rounded-full bg-orange-50 px-2.5 py-1 text-xs font-medium text-orange-600">
                NAT / 建站型
              </span>
            ) : (
              <span className="text-sm text-gray-600">独立 IP × {ipCount}</span>
            )}
          </div>
        </div>

        {/* 上行带宽 */}
        {inBwField?.type === "slider" ? (
          <SliderField
            field={inBwField}
            value={sliderValues["in_bw"] ?? inBwField.slider_min ?? 0}
            onChange={(v) => setSliderValues((prev) => ({ ...prev, in_bw: v }))}
          />
        ) : (
          <div className="flex items-center justify-between">
            <span className="text-sm font-medium text-gray-700">上行带宽</span>
            <span className="text-sm text-gray-600">
              {inBwFixed != null ? `${inBwFixed} Mbps` : "—"}
            </span>
          </div>
        )}

        {/* 下行带宽 */}
        {outBwField?.type === "slider" ? (
          <SliderField
            field={outBwField}
            value={sliderValues["out_bw"] ?? outBwField.slider_min ?? 0}
            onChange={(v) => setSliderValues((prev) => ({ ...prev, out_bw: v }))}
          />
        ) : (
          <div className="flex items-center justify-between">
            <span className="text-sm font-medium text-gray-700">下行带宽</span>
            <span className="text-sm text-gray-600">
              {outBwFixed != null ? `${outBwFixed} Mbps` : "—"}
            </span>
          </div>
        )}

      </div>
    </SectionCard>
  )
}

function BillRow({ label, value }: { label: string; value: React.ReactNode }) {
  return (
    <div className="flex items-start justify-between py-2 gap-2">
      <span className="text-xs text-gray-400 shrink-0 pt-0.5">{label}</span>
      <span className="text-xs text-gray-700 text-right break-all">{value}</span>
    </div>
  )
}
