"use client";

import { ChevronDown, ChevronUp, Layers3, ZoomIn, ZoomOut } from "lucide-react";
import { memo, useEffect, useId, useRef, useState } from "react";

import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { Slider } from "@/components/ui/slider";
import {
  MODULES,
  QUALITIES,
  QUALITY_BY_ID,
  iconFor,
} from "@/app/lib/factorio-data";
import {
  moduleIsAllowed,
  resolveAutoModules,
  toDisplayRate,
  unitLabel,
} from "@/app/lib/calculator";
import { intlLocale, localizedName, qualityLabel, tr } from "@/app/lib/i18n";
import type {
  BeaconLayoutResult,
  Locale,
  Machine,
  MaterialFlow,
  ModuleFamily,
  ModuleSelection,
  QualityId,
  RateUnit,
  Recipe,
} from "@/app/lib/types";
import { FactorioIcon } from "./factorio-icon";

export function formatNumber(
  value: number,
  locale: Locale = "en",
  digits = 3,
): string {
  if (!Number.isFinite(value)) return "—";
  const abs = Math.abs(value);
  if (abs > 0 && abs < 0.001) return value.toExponential(2);
  return new Intl.NumberFormat(intlLocale(locale), {
    maximumFractionDigits: abs >= 1000 ? 1 : digits,
  }).format(value);
}
export function formatPower(kw: number, locale: Locale = "en"): string {
  if (kw >= 1e6) return `${formatNumber(kw / 1e6, locale, 2)} GW`;
  if (kw >= 1e3) return `${formatNumber(kw / 1e3, locale, 2)} MW`;
  return `${formatNumber(kw, locale, 1)} kW`;
}
export function formatMw(mw: number, locale: Locale = "en"): string {
  return mw >= 1000
    ? `${formatNumber(mw / 1000, locale, 2)} GW`
    : `${formatNumber(mw, locale, 2)} MW`;
}

export function SectionTitle({
  number,
  title,
  note,
  icons = [],
}: {
  number: string;
  title: string;
  note?: string;
  icons?: string[];
}) {
  return (
    <div className="mb-4 flex items-start justify-between gap-3">
      <div className="flex min-w-0 items-center gap-3">
        <span className="flex size-7 shrink-0 items-center justify-center rounded-md border border-[#f7a72d]/35 bg-[#f7a72d]/10 font-mono text-xs font-bold text-[#f7a72d]">
          {number}
        </span>
        <h2 className="truncate text-[15px] font-semibold tracking-wide text-zinc-100">
          {title}
        </h2>
        {icons.length ? (
          <span className="hidden items-center gap-1 sm:flex">
            {icons.map((icon, index) => (
              <FactorioIcon
                key={`${icon}:${index}`}
                src={icon}
                alt=""
                size="sm"
                className="rounded bg-[#17191b]"
              />
            ))}
          </span>
        ) : null}
      </div>
      {note ? (
        <span className="shrink-0 font-mono text-[9px] uppercase tracking-wider text-zinc-600">
          {note}
        </span>
      ) : null}
    </div>
  );
}
export function FieldLabel({
  children,
  detail,
}: {
  children: React.ReactNode;
  detail?: string;
}) {
  return (
    <div className="mb-2 flex items-center justify-between gap-3">
      <label className="text-[13px] font-medium text-zinc-300">
        {children}
      </label>
      {detail ? (
        <span className="font-mono text-[9px] text-zinc-600">{detail}</span>
      ) : null}
    </div>
  );
}
export function QualitySelect({
  value,
  onChange,
  locale,
  disabled = false,
  includeTotal = false,
  maxQuality,
}: {
  value: QualityId | "total";
  onChange: (value: QualityId | "total") => void;
  locale: Locale;
  disabled?: boolean;
  includeTotal?: boolean;
  maxQuality?: QualityId;
}) {
  const cap = maxQuality
    ? QUALITIES.findIndex((q) => q.id === maxQuality)
    : QUALITIES.length - 1;
  return (
    <Select
      value={value}
      onValueChange={(next) => onChange(next as QualityId | "total")}
      disabled={disabled}
    >
      <SelectTrigger className="h-10 w-full border-white/10 bg-[#17191b] text-zinc-200">
        <SelectValue />
      </SelectTrigger>
      <SelectContent className="border-white/10 bg-[#17191b] text-zinc-100">
        {includeTotal ? (
          <SelectItem value="total">
            <span className="flex items-center gap-2">
              <Layers3 className="size-4" />
              {tr(locale, "allQualities")}
            </span>
          </SelectItem>
        ) : null}
        {QUALITIES.slice(0, cap + 1).map((quality) => (
          <SelectItem key={quality.id} value={quality.id}>
            <span className="flex items-center gap-2">
              <FactorioIcon src={quality.icon} alt="" size="sm" />
              <span style={{ color: quality.color }}>
                {qualityLabel(quality.id, locale)}
              </span>
            </span>
          </SelectItem>
        ))}
      </SelectContent>
    </Select>
  );
}
export function UnitSelect({
  value,
  onChange,
}: {
  value: RateUnit;
  onChange: (unit: RateUnit) => void;
}) {
  return (
    <Select value={value} onValueChange={(next) => onChange(next as RateUnit)}>
      <SelectTrigger className="h-10 w-[88px] border-white/10 bg-[#17191b] font-mono text-zinc-100">
        <SelectValue />
      </SelectTrigger>
      <SelectContent className="border-white/10 bg-[#17191b] text-zinc-100">
        <SelectItem value="s">/s</SelectItem>
        <SelectItem value="min">/min</SelectItem>
        <SelectItem value="h">/h</SelectItem>
      </SelectContent>
    </Select>
  );
}

export function SmartNumberInput({
  value,
  onValueChange,
  min,
  max,
  step = 1,
  className = "",
  ariaLabel,
}: {
  value: number;
  onValueChange: (value: number) => void;
  min?: number;
  max?: number;
  step?: number;
  className?: string;
  ariaLabel?: string;
}) {
  const inputRef = useRef<HTMLInputElement>(null);
  const wheelState = useRef({ last: 0, streak: 0, direction: 0 });
  const currentValue = useRef(value);
  useEffect(() => {
    currentValue.current = value;
  }, [value]);
  const clamp = (next: number) =>
    Math.min(max ?? Infinity, Math.max(min ?? -Infinity, next));
  const nudge = (direction: number, multiplier = 1) => {
    const precision = Math.max(0, (String(step).split(".")[1] ?? "").length);
    const next = Number(
      clamp(currentValue.current + direction * step * multiplier).toFixed(
        precision + 2,
      ),
    );
    currentValue.current = next;
    onValueChange(next);
  };
  useEffect(() => {
    const input = inputRef.current;
    if (!input) return;
    const handleWheel = (event: WheelEvent) => {
      // A native non-passive listener is required here. React's delegated wheel
      // listener may be passive, which allowed the settings column/page to move
      // while the number itself was changing.
      event.preventDefault();
      event.stopPropagation();
      const now = performance.now();
      const direction = event.deltaY < 0 ? 1 : -1;
      const state = wheelState.current;
      state.streak =
        direction === state.direction && now - state.last < 420
          ? state.streak + 1
          : 0;
      state.direction = direction;
      state.last = now;
      const multiplier =
        state.streak > 22
          ? 25
          : state.streak > 12
            ? 10
            : state.streak > 6
              ? 5
              : state.streak > 2
                ? 2
                : 1;
      const precision = Math.max(0, (String(step).split(".")[1] ?? "").length);
      const next = Number(
        Math.min(
          max ?? Infinity,
          Math.max(
            min ?? -Infinity,
            currentValue.current + direction * step * multiplier,
          ),
        ).toFixed(precision + 2),
      );
      currentValue.current = next;
      onValueChange(next);
    };
    input.addEventListener("wheel", handleWheel, { passive: false });
    return () => input.removeEventListener("wheel", handleWheel);
  }, [max, min, onValueChange, step]);
  return (
    <div className={`smart-number editable-control ${className}`}>
      <input
        ref={inputRef}
        aria-label={ariaLabel}
        type="number"
        value={Number.isFinite(value) ? value : 0}
        min={min}
        max={max}
        step={step}
        onChange={(event) => {
          const next = clamp(Number(event.target.value));
          currentValue.current = next;
          onValueChange(next);
        }}
      />
      <span className="smart-number-buttons">
        <button
          type="button"
          tabIndex={-1}
          aria-label="Increase"
          onClick={() => nudge(1)}
        >
          <ChevronUp />
        </button>
        <button
          type="button"
          tabIndex={-1}
          aria-label="Decrease"
          onClick={() => nudge(-1)}
        >
          <ChevronDown />
        </button>
      </span>
    </div>
  );
}

export function BeaconCountSelect({
  value,
  maximum,
  onChange,
  disabled = false,
}: {
  value: number;
  maximum: number;
  onChange: (value: number) => void;
  disabled?: boolean;
}) {
  const safeValue = Math.max(0, Math.min(maximum, Math.floor(value)));
  return (
    <Select
      value={String(safeValue)}
      disabled={disabled}
      onValueChange={(next) => onChange(Number(next))}
    >
      <SelectTrigger className="h-10 w-full border-white/10 bg-[#17191b] text-zinc-100">
        <SelectValue />
      </SelectTrigger>
      <SelectContent>
        {Array.from({ length: maximum + 1 }, (_, count) => (
          <SelectItem key={count} value={String(count)}>
            <span className="flex items-center gap-2">
              <FactorioIcon src={iconFor("beacon")} alt="" size="sm" />
              <span>{count}</span>
            </span>
          </SelectItem>
        ))}
      </SelectContent>
    </Select>
  );
}

function moduleId(selection: { family: ModuleFamily; tier: number }) {
  return `${selection.family}-module${selection.tier === 1 ? "" : `-${selection.tier}`}`;
}
export type ModuleConfig = {
  mode: "auto" | "manual";
  families: ModuleFamily[];
  tier: 1 | 2 | 3;
  quality: QualityId;
  manual: Array<ModuleSelection | null>;
};
export function resolvedModules(
  config: ModuleConfig,
  slots: number,
  machine: Machine,
  recipe: Recipe,
  beacon = false,
) {
  if (config.mode === "manual")
    return Array.from(
      { length: slots },
      (_, index) => config.manual[index] ?? null,
    );
  return resolveAutoModules(
    config.families,
    config.tier,
    config.quality,
    slots,
    machine,
    recipe,
    beacon,
  );
}
export function ModuleConfigurator({
  title,
  locale,
  slots,
  machine,
  recipe,
  beacon = false,
  config,
  onChange,
  allowedFamilies,
  autoAllowedFamilies,
}: {
  title: string;
  locale: Locale;
  slots: number;
  machine: Machine;
  recipe: Recipe;
  beacon?: boolean;
  config: ModuleConfig;
  onChange: (next: ModuleConfig) => void;
  allowedFamilies?: ModuleFamily[];
  autoAllowedFamilies?: ModuleFamily[];
}) {
  const families = (allowedFamilies ??
    (beacon
      ? ["speed", "efficiency"]
      : ["productivity", "speed", "quality", "efficiency"])) as ModuleFamily[];
  const automaticFamilies = autoAllowedFamilies ?? families;
  const occupiedSlots =
    config.mode === "manual"
      ? Array.from({ length: slots }, (_, index) => config.manual[index] ?? null)
          .filter(Boolean).length
      : config.families.length
        ? slots
        : 0;
  if (!slots)
    return (
      <div className="module-panel rounded-lg border border-dashed border-white/10 p-3 text-xs text-zinc-500">
        {title}: 0 {tr(locale, "slots")}
      </div>
    );
  return (
    <div className="module-panel rounded-xl border border-white/8 bg-[#111315]/70 p-3">
      <div className="mb-3 flex items-center justify-between gap-2">
        <span className="text-sm font-medium text-zinc-200">
          {title}{" "}
          <span className="font-mono text-[10px] text-zinc-600">
            {beacon
              ? `· ${occupiedSlots}/2 ${tr(locale, "occupiedSlots")} · ${tr(locale, "slotsPerBeacon")}`
              : `· ${slots} ${tr(locale, "slots")}`}
          </span>
        </span>
        <div className="flex rounded-md border border-white/8 bg-[#17191b] p-0.5">
          {(["auto", "manual"] as const).map((mode) => (
            <button
              type="button"
              key={mode}
              onClick={() => onChange({ ...config, mode })}
              className={`rounded px-2 py-1 font-mono text-[9px] uppercase ${config.mode === mode ? "bg-[#303439] text-[#f7a72d]" : "text-zinc-600"}`}
            >
              {tr(locale, mode === "auto" ? "automatic" : "manual")}
            </button>
          ))}
        </div>
      </div>
      {config.mode === "auto" ? (
        <div className="space-y-3">
          <div className="grid grid-cols-2 gap-2">
            {automaticFamilies.map((family) => {
              const selection = {
                family,
                tier: config.tier,
                quality: config.quality,
              };
              const allowed = moduleIsAllowed(
                selection,
                machine,
                recipe,
                beacon,
              );
              const active = config.families.includes(family);
              return (
                <button
                  type="button"
                  key={family}
                  disabled={!allowed}
                  onClick={() =>
                    onChange({
                      ...config,
                      families: active
                        ? config.families.filter((f) => f !== family)
                        : [...config.families, family],
                    })
                  }
                  className={`flex items-center gap-2 rounded-lg border p-2 text-left disabled:opacity-30 ${active ? "border-[#f7a72d]/50 bg-[#f7a72d]/10" : "border-white/8 bg-[#17191b]"}`}
                >
                  <FactorioIcon
                    src={iconFor(moduleId(selection))}
                    alt=""
                    size="md"
                  />
                  <span className="truncate text-xs">
                    {localizedName(moduleId(selection), locale, "item")}
                  </span>
                </button>
              );
            })}
          </div>
          <div className="grid grid-cols-2 gap-2">
            <div>
              <FieldLabel>{tr(locale, "tier")}</FieldLabel>
              <Select
                value={String(config.tier)}
                onValueChange={(v) =>
                  onChange({ ...config, tier: Number(v) as 1 | 2 | 3 })
                }
              >
                <SelectTrigger className="h-10 border-white/10 bg-[#17191b]">
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  {[1, 2, 3].map((t) => (
                    <SelectItem key={t} value={String(t)}>
                      T{t}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
            <div>
              <FieldLabel>{tr(locale, "moduleQuality")}</FieldLabel>
              <QualitySelect
                value={config.quality}
                onChange={(v) =>
                  onChange({ ...config, quality: v as QualityId })
                }
                locale={locale}
              />
            </div>
          </div>
        </div>
      ) : (
        <div className="space-y-2">
          {Array.from({ length: slots }, (_, index) => {
            const selection = config.manual[index] ?? null;
            const valid = MODULES.filter(
              (module) =>
                families.includes(module.family) &&
                moduleIsAllowed(
                  {
                    family: module.family,
                    tier: module.tier,
                    quality: selection?.quality ?? "normal",
                  },
                  machine,
                  recipe,
                  beacon,
                ),
            );
            return (
              <div
                key={index}
                className="grid grid-cols-[28px_1fr_112px] gap-2 rounded-lg border border-white/7 bg-[#17191b] p-2"
              >
                <span className="flex size-7 items-center justify-center rounded bg-white/5 font-mono text-[10px] text-zinc-500">
                  {index + 1}
                </span>
                <Select
                  value={
                    selection
                      ? `${selection.family}:${selection.tier}`
                      : "empty"
                  }
                  onValueChange={(value) => {
                    const manual = Array.from(
                      { length: slots },
                      (_, slot) => config.manual[slot] ?? null,
                    );
                    if (value === "empty") manual[index] = null;
                    else {
                      const [family, tier] = value.split(":") as [
                        ModuleFamily,
                        "1" | "2" | "3",
                      ];
                      manual[index] = {
                        family,
                        tier: Number(tier) as 1 | 2 | 3,
                        quality: selection?.quality ?? "normal",
                      };
                    }
                    onChange({ ...config, manual });
                  }}
                >
                  <SelectTrigger className="h-9 min-w-0 border-white/10 bg-[#111315] text-xs">
                    <SelectValue />
                  </SelectTrigger>
                  <SelectContent className="max-h-72">
                    {<SelectItem value="empty">—</SelectItem>}
                    {valid.map((module) => (
                      <SelectItem
                        key={`${module.family}:${module.tier}`}
                        value={`${module.family}:${module.tier}`}
                      >
                        <span className="flex items-center gap-2">
                          <FactorioIcon src={module.icon} alt="" size="sm" />
                          {localizedName(moduleId(module), locale, "item")}
                        </span>
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
                <QualitySelect
                  value={selection?.quality ?? "normal"}
                  onChange={(q) => {
                    if (!selection) return;
                    const manual = [...config.manual];
                    manual[index] = { ...selection, quality: q as QualityId };
                    onChange({ ...config, manual });
                  }}
                  disabled={!selection}
                  locale={locale}
                />
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}

export function CollapsiblePanel({
  defaultOpen = false,
  children,
  ...props
}: Omit<React.ComponentPropsWithoutRef<"details">, "open" | "onToggle"> & {
  defaultOpen?: boolean;
}) {
  const [isOpen, setIsOpen] = useState(defaultOpen);
  return (
    <details
      {...props}
      open={isOpen}
      onToggle={(event) => setIsOpen(event.currentTarget.open)}
    >
      {children}
    </details>
  );
}

export function ExpandableSection({
  title,
  number,
  icons = [],
  children,
  open = true,
  className = "",
}: {
  title: string;
  number?: string;
  icons?: string[];
  children: React.ReactNode;
  open?: boolean;
  className?: string;
}) {
  return (
    <CollapsiblePanel
      className={`hierarchy-panel collapsible-panel group rounded-2xl border border-white/8 bg-[#111315] ${className}`}
      defaultOpen={open}
    >
      <summary className="collapsible-summary list-none p-4">
        <span className="summary-leading flex min-w-0 items-center gap-2">
          {number ? (
            <span className="flex size-7 shrink-0 items-center justify-center rounded-md border border-[#f7a72d]/35 bg-[#f7a72d]/10 font-mono text-xs font-bold text-[#f7a72d]">
              {number}
            </span>
          ) : null}
          <span className="truncate text-[15px] font-semibold">{title}</span>
          <span className="flex gap-1">
            {icons.map((icon, index) => (
              <FactorioIcon
                key={`${icon}:${index}`}
                src={icon}
                alt=""
                size="sm"
              />
            ))}
          </span>
        </span>
        <span className="summary-trailing">
          <ChevronDown className="details-chevron size-4 text-zinc-600 transition" />
        </span>
      </summary>
      <div className="hierarchy-panel-body space-y-3 border-t border-white/7 p-4">{children}</div>
    </CollapsiblePanel>
  );
}

function QualityMarkedIcon({
  icon,
  quality,
}: {
  icon: string;
  quality: QualityId;
}) {
  const definition = QUALITY_BY_ID.get(quality)!;
  return (
    <span
      className="relative inline-flex rounded-md border p-0.5"
      style={{
        borderColor: `${definition.color}99`,
        boxShadow: `0 0 12px ${definition.color}22`,
      }}
    >
      <FactorioIcon src={icon} alt="" size="md" />
      <FactorioIcon
        src={definition.icon}
        alt=""
        size="sm"
        className="absolute -bottom-1 -right-1 rounded-full bg-[#0b0d0e]"
      />
    </span>
  );
}

export function MaterialRowContent({
  flow,
  unit,
  locale,
}: {
  flow: MaterialFlow;
  unit: RateUnit;
  locale: Locale;
}) {
  const qualityAmounts = flow.amounts.filter(
    (entry): entry is typeof entry & { quality: QualityId } =>
      Boolean(entry.quality),
  );
  return (
    <>
      <div className="flex min-w-[150px] flex-1 items-center gap-3">
        <FactorioIcon src={flow.icon} alt="" size="lg" />
        <div className="min-w-0">
          <p className="whitespace-normal break-words text-sm font-medium leading-tight text-zinc-100">
            {localizedName(flow.id, locale, flow.type)}
          </p>
          {qualityAmounts.length > 1 ? (
            <p className="font-mono text-[9px] text-zinc-600">
              Σ {formatNumber(toDisplayRate(flow.total, unit), locale)}{" "}
              {unitLabel(unit)}
            </p>
          ) : null}
        </div>
      </div>
      {qualityAmounts.length ? (
        <div className="quality-output-grid">
          {qualityAmounts.map((entry) => {
            const quality = QUALITY_BY_ID.get(entry.quality)!;
            return (
              <span
                key={entry.quality}
                className="quality-output-chip"
                data-quality={entry.quality}
                style={{ borderColor: `${quality.color}55` }}
              >
                <QualityMarkedIcon icon={flow.icon} quality={entry.quality} />
                <span>
                  <small style={{ color: quality.color }}>
                    {qualityLabel(entry.quality, locale)}
                  </small>
                  <strong style={{ color: quality.color }}>
                    {formatNumber(toDisplayRate(entry.amount, unit), locale)}
                  </strong>
                  <em>{unitLabel(unit)}</em>
                </span>
              </span>
            );
          })}
        </div>
      ) : (
        <div className="text-right">
          <p className="font-mono text-sm font-semibold">
            {formatNumber(toDisplayRate(flow.total, unit), locale)}
          </p>
          <p className="font-mono text-[9px] text-zinc-600">
            {unitLabel(unit)}
          </p>
        </div>
      )}
    </>
  );
}

export function MaterialRow({
  flow,
  unit,
  locale,
  onClick,
}: {
  flow: MaterialFlow;
  unit: RateUnit;
  locale: Locale;
  onClick?: () => void;
}) {
  const content = (
    <MaterialRowContent flow={flow} unit={unit} locale={locale} />
  );
  return onClick ? (
    <button
      type="button"
      onClick={onClick}
      title={tr(locale, "clickMaterial")}
      className="material-panel flex w-full flex-wrap items-center gap-3 rounded-lg border border-white/7 bg-[#151719] px-3 py-2.5 text-left transition hover:border-[#f7a72d]/40"
    >
      {content}
    </button>
  ) : (
    <div className="material-panel flex flex-wrap items-center gap-3 rounded-lg border border-white/7 bg-[#151719] px-3 py-2.5">
      {content}
    </div>
  );
}
export function MetricCard({
  icon,
  label,
  value,
  detail,
}: {
  icon: React.ReactNode;
  label: string;
  value: string;
  detail?: string;
}) {
  return (
    <div className="metric-card rounded-xl border border-white/8 bg-[#17191b] p-4">
      <div className="mb-2 flex items-center justify-between text-zinc-500">
        <span className="font-mono text-[9px] uppercase tracking-wider">
          {label}
        </span>
        {icon}
      </div>
      <p className="text-xl font-semibold">{value}</p>
      {detail ? <p className="mt-1 text-xs text-zinc-500">{detail}</p> : null}
    </div>
  );
}

function GeometryDesignImpl({
  layout,
  machine,
  locale,
  title,
  subtitle,
}: {
  layout: BeaconLayoutResult;
  machine?: Machine;
  locale: Locale;
  title?: string;
  subtitle?: string;
}) {
  const [zoom, setZoom] = useState(100);
  const patternId = `tile-grid-${useId().replaceAll(":", "")}`;
  const tile = (12 * zoom) / 100;
  const width = Math.max(
    220,
    (layout.bounds.maxX - layout.bounds.minX + 2) * tile,
  );
  const height = Math.max(
    140,
    (layout.bounds.maxY - layout.bounds.minY + 2) * tile,
  );
  const offsetX = -layout.bounds.minX + 1;
  const offsetY = -layout.bounds.minY + 1;
  return (
    <div className="geometry-panel rounded-xl border border-white/8 bg-[#0d0f10] p-3">
      <div className="mb-3 flex flex-wrap items-center justify-between gap-3">
        <div>
          <p className="text-sm font-medium">
            {title ??
              `${tr(locale, "geometryCheck")} · ${tr(locale, "beaconDesign")}`}
          </p>
          <p className="font-mono text-[9px] text-zinc-600">
            {subtitle ??
              `${layout.uniqueBeacons} ${tr(locale, "beacons")} · Ø ${formatNumber(layout.average, locale, 2)} (${layout.min}–${layout.max})`}
          </p>
        </div>
        <div className="flex items-center gap-2">
          <ZoomOut className="size-3.5 text-zinc-500" />
          <Slider
            aria-label={tr(locale, "zoom")}
            value={[zoom]}
            min={40}
            max={400}
            step={10}
            onValueChange={(v) => setZoom(v[0])}
            className="w-28"
          />
          <ZoomIn className="size-3.5 text-zinc-500" />
          <span className="w-10 font-mono text-[10px] text-zinc-500">
            {zoom}%
          </span>
        </div>
      </div>
      <div className="max-h-[520px] overflow-auto rounded-lg border border-white/7 bg-[#080909]">
        <svg
          width={width}
          height={height}
          role="img"
          aria-label={tr(locale, "beaconDesign")}
          style={{ minWidth: width }}
        >
          <defs>
            <pattern
              id={patternId}
              width={tile}
              height={tile}
              patternUnits="userSpaceOnUse"
            >
              <path
                d={`M ${tile} 0 L 0 0 0 ${tile}`}
                fill="none"
                stroke="rgba(255,255,255,.045)"
                strokeWidth=".6"
              />
            </pattern>
          </defs>
          <rect width="100%" height="100%" fill={`url(#${patternId})`} />
          {layout.placements
            .filter((p) => p.kind === "link")
            .map((p, i) => {
              const x = (p.x + offsetX) * tile,
                y = (p.y + offsetY) * tile;
              const linkLabel =
                p.label ??
                (p.entityId
                  ? localizedName(
                      p.entityId,
                      locale,
                      p.entityId === "steam" ||
                        p.entityId.includes("water") ||
                        p.entityId.includes("fluoroketone")
                        ? "fluid"
                        : "entity",
                    )
                  : undefined);
              return (
                <g key={`l${i}`}>
                  <rect
                    x={x}
                    y={y}
                    width={p.width * tile}
                    height={p.height * tile}
                    rx={tile * 0.2}
                    fill={p.tone === "heat" ? "#7f3f25" : "#24586b"}
                    opacity=".75"
                  />
                  <text
                    x={x + (p.width * tile) / 2}
                    y={y + (p.height * tile) / 2 + 3}
                    textAnchor="middle"
                    fill="#fff"
                    fontSize={Math.max(7, tile * 0.42)}
                  >
                    {linkLabel}
                  </text>
                </g>
              );
            })}
          {layout.placements
            .filter((p) => p.kind === "entity")
            .map((p, i) => {
              const x = (p.x + offsetX) * tile,
                y = (p.y + offsetY) * tile;
              const color =
                p.tone === "heat"
                  ? "#e8793f"
                  : p.tone === "fluid"
                    ? "#69c5df"
                    : p.tone === "storage"
                      ? "#9c73c7"
                      : "#f7a72d";
              const entityLabel = p.entityId
                ? localizedName(p.entityId, locale, "entity")
                : p.label;
              const rotation =
                p.direction === "east"
                  ? 90
                  : p.direction === "south"
                    ? 180
                    : p.direction === "west"
                      ? 270
                      : 0;
              return (
                <g key={`e${i}`}>
                  <rect
                    x={x}
                    y={y}
                    width={p.width * tile}
                    height={p.height * tile}
                    rx={3}
                    fill="#171a1d"
                    stroke={color}
                    strokeOpacity=".75"
                  />
                  <image
                    href={iconFor(p.entityId ?? "constant-combinator")}
                    x={x + tile * 0.3}
                    y={y + tile * 0.3}
                    width={Math.max(tile, p.width * tile - tile * 0.6)}
                    height={Math.max(tile, p.height * tile - tile * 0.6)}
                    transform={
                      rotation
                        ? `rotate(${rotation} ${x + (p.width * tile) / 2} ${y + (p.height * tile) / 2})`
                        : undefined
                    }
                  />
                  {p.direction ? (
                    <g aria-hidden="true">
                      <circle
                        cx={x + p.width * tile - tile * 0.42}
                        cy={y + tile * 0.42}
                        r={Math.max(5, tile * 0.34)}
                        fill="#080909"
                        stroke={color}
                        strokeWidth="1"
                      />
                      <text
                        x={x + p.width * tile - tile * 0.42}
                        y={y + tile * 0.42 + Math.max(2.5, tile * 0.13)}
                        textAnchor="middle"
                        fill="#fff"
                        fontSize={Math.max(8, tile * 0.46)}
                        fontWeight="700"
                      >
                        {p.direction === "north"
                          ? "↑"
                          : p.direction === "east"
                            ? "→"
                            : p.direction === "south"
                              ? "↓"
                              : "←"}
                      </text>
                    </g>
                  ) : null}
                  <title>
                    {entityLabel}
                    {p.direction ? ` · ${p.direction}` : ""}
                  </title>
                </g>
              );
            })}
          {layout.placements
            .filter((p) => p.kind === "beacon")
            .map((p, i) => {
              const x = (p.x + offsetX) * tile,
                y = (p.y + offsetY) * tile;
              return (
                <g key={`b${i}`}>
                  <rect
                    x={x}
                    y={y}
                    width={p.width * tile}
                    height={p.height * tile}
                    rx={2}
                    fill="#17232a"
                    stroke="#69c5df"
                    strokeOpacity=".55"
                  />
                  <image
                    href={iconFor("beacon")}
                    x={x + tile * 0.35}
                    y={y + tile * 0.35}
                    width={p.width * tile - tile * 0.7}
                    height={p.height * tile - tile * 0.7}
                  />
                </g>
              );
            })}
          {machine
            ? layout.placements
                .filter((p) => p.kind === "machine")
                .map((p, i) => {
                  const x = (p.x + offsetX) * tile,
                    y = (p.y + offsetY) * tile;
                  const count =
                    layout.counts[p.machineIndex ?? i] ??
                    Math.round(layout.average);
                  return (
                    <g key={`m${i}`}>
                      <rect
                        x={x}
                        y={y}
                        width={p.width * tile}
                        height={p.height * tile}
                        rx={3}
                        fill="#2a2115"
                        stroke="#f7a72d"
                        strokeOpacity=".75"
                      />
                      <image
                        href={machine.icon}
                        x={x + tile * 0.35}
                        y={y + tile * 0.35}
                        width={Math.max(tile, p.width * tile - tile * 0.7)}
                        height={Math.max(tile, p.height * tile - tile * 0.7)}
                      />
                      <circle
                        cx={x + p.width * tile - tile * 0.45}
                        cy={y + tile * 0.45}
                        r={Math.max(7, tile * 0.42)}
                        fill="#0b0d0e"
                        stroke="#f7a72d"
                      />
                      <text
                        x={x + p.width * tile - tile * 0.45}
                        y={y + tile * 0.45 + 3.5}
                        textAnchor="middle"
                        fill="#fff"
                        fontSize={Math.max(9, tile * 0.55)}
                        fontWeight="700"
                      >
                        {count}
                      </text>
                    </g>
                  );
                })
            : null}
        </svg>
      </div>
      {layout.extrapolated ? (
        <p className="mt-2 text-[10px] text-zinc-600">
          {tr(locale, "previewCapped")}
        </p>
      ) : null}
    </div>
  );
}

export const GeometryDesign = memo(GeometryDesignImpl);
