"use client";

import {
  AlertTriangle,
  ChevronDown,
  CircleGauge,
  CircleHelp,
  Factory,
  FlaskConical,
  Gauge,
  Languages,
  Plus,
  Recycle,
  RotateCcw,
  Rocket as RocketIcon,
  Sparkles,
  Trash2,
  Zap,
} from "lucide-react";
import {
  Suspense,
  lazy,
  memo,
  useCallback,
  useEffect,
  useMemo,
  useState,
} from "react";

import { Button } from "@/components/ui/button";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  DATA_META,
  PRODUCTS,
  PRODUCT_BY_KEY,
  RECIPE_BY_ID,
  downstreamProducts,
  iconFor,
  iconForGroup,
  machinesForRecipe,
  preferredChainRecipeForProduct,
  preferredMachineForRecipe,
  preferredRecipeForProduct,
} from "@/app/lib/factorio-data";
import {
  calculate,
  moduleIsAllowed,
  toDisplayRate,
  unitLabel,
} from "@/app/lib/calculator";
import { DEFAULT_LOGISTICS, calculateLogistics } from "@/app/lib/logistics";
import { buildProductionChain } from "@/app/lib/production-chain";
import publicLocaleJson from "@/app/data/public-locales.json";
import {
  DEFAULT_BLUEPRINT_BLOCK_SETTINGS,
  type BlueprintBlockSettings,
} from "@/app/lib/blueprint-contract";
import {
  DEFAULT_MACHINE_PRIORITIES,
  DEFAULT_UNLOCKED_MACHINE_IDS,
  preferredUnlockedChainRoute,
  rankedMachinesForRecipe,
} from "@/app/lib/chain-machines";
import {
  LOCALE_OPTIONS,
  groupLabel,
  languageLabel,
  localizeCoreMessage,
  localizedName,
  tr,
} from "@/app/lib/i18n";
import type {
  CalculatorInput,
  CalculatorSection,
  ChainMasterSettings,
  ChainOverride,
  EnergySourceSelection,
  InputConstraint,
  ItemGroupId,
  Locale,
  LogisticsSettings,
  MaterialFlow,
  ModuleFamily,
  ProductOption,
  QualityId,
  RateUnit,
  Recipe,
} from "@/app/lib/types";
import {
  EnergyWorkspace,
  FactoryTotalsPanel,
  ChainMasterPanel,
  LogisticsPanel,
  ProductionChainPanel,
  ScienceWorkspace,
} from "./advanced-panels";
import {
  ExpandableSection,
  CollapsiblePanel,
  BeaconCountSelect,
  FieldLabel,
  MaterialRow,
  MaterialRowContent,
  MetricCard,
  ModuleConfigurator,
  type ModuleConfig,
  QualitySelect,
  SectionTitle,
  SmartNumberInput,
  UnitSelect,
  formatNumber,
  formatPower,
  resolvedModules,
} from "./calculator-widgets";
import {
  BLUEPRINT_GENERATOR_ENABLED,
  ProductionGeometry,
} from "@blueprint/production-geometry";
import { FactorioIcon } from "./factorio-icon";
import { RecyclingWorkspace } from "./recycling-workspace";
import { ReleaseFooter } from "./release-footer";
import { RocketFreightWorkspace } from "./rocket-freight-workspace";
import { SearchPicker, type SearchPickerGroup } from "./search-picker";

const GROUPS: ItemGroupId[] = [
  "logistics",
  "production",
  "intermediate-products",
  "space",
  "combat",
  "fluids",
];
const DEFAULT_PRODUCT = "item:advanced-circuit";
const selectClass = "h-10 w-full border-white/10 bg-[#17191b] text-zinc-100";
const HelpWorkspace = lazy(() =>
  import("./help-workspace").then((module) => ({
    default: module.HelpWorkspace,
  })),
);

export type CalculatorAppProps = {
  initialLocale?: Locale;
  publicLocaleRouting?: boolean;
};

const PUBLIC_LOCALE_META = publicLocaleJson as Record<
  Locale,
  {
    path: string;
    title: string;
    description: string;
    ogLocale: string;
    noscript: string;
  }
>;

function setMetaContent(selector: string, content: string) {
  document.head.querySelector<HTMLMetaElement>(selector)?.setAttribute("content", content);
}

function updatePublicLocaleMetadata(locale: Locale) {
  const meta = PUBLIC_LOCALE_META[locale];
  const canonicalUrl = `https://factoriocalculatorapp.com${meta.path}`;

  if (window.location.pathname !== meta.path) {
    window.history.replaceState(
      window.history.state,
      "",
      `${meta.path}${window.location.search}${window.location.hash}`,
    );
  }
  document.title = meta.title;
  document.documentElement.lang = locale;
  document.head
    .querySelector<HTMLLinkElement>('link[rel="canonical"]')
    ?.setAttribute("href", canonicalUrl);
  setMetaContent('meta[name="description"]', meta.description);
  setMetaContent('meta[property="og:title"]', meta.title);
  setMetaContent('meta[property="og:description"]', meta.description);
  setMetaContent('meta[property="og:url"]', canonicalUrl);
  setMetaContent('meta[property="og:locale"]', meta.ogLocale);
  setMetaContent('meta[name="twitter:title"]', meta.title);
  setMetaContent('meta[name="twitter:description"]', meta.description);
}

function sameEnergySource(
  first: EnergySourceSelection | undefined,
  second: EnergySourceSelection | undefined,
) {
  return (
    first === second ||
    (Boolean(first) &&
      Boolean(second) &&
      first!.id === second!.id &&
      first!.label === second!.label &&
      first!.icon === second!.icon &&
      first!.directKw === second!.directKw &&
      first!.chainKw === second!.chainKw &&
      first!.includeDirect === second!.includeDirect &&
      first!.includeChain === second!.includeChain &&
      first!.mode === second!.mode)
  );
}

type ProductionTargetState = {
  id: string;
  productKey: string;
  recipeId: string;
  machineId: string;
  amount: number;
  unit: RateUnit;
  rateMode: "output" | "input";
  constraints: InputConstraint[];
  machineQuality: QualityId;
  inputQuality: QualityId;
  outputQuality: QualityId | "total";
  maxQuality: QualityId;
  machineConfig: ModuleConfig;
  beaconConfig: ModuleConfig;
  beaconCount: number;
  beaconQuality: QualityId;
  chainEnabled: boolean;
  showChain: boolean;
  resultCollapsed: boolean;
  chainMaster: ChainMasterSettings;
  chainOverrides: Record<string, ChainOverride>;
  logistics: LogisticsSettings;
  blueprintSettings: BlueprintBlockSettings;
  includeDirectEnergy: boolean;
  includeChainEnergy: boolean;
};

function makeChainMaster(qualityMode: boolean): ChainMasterSettings {
  return {
    preferredMachineId: "auto",
    miningDrillId: "big-mining-drill",
    miningModuleFamily: qualityMode ? "quality" : "none",
    miningModuleTier: 3,
    miningModuleQuality: "normal",
    unlockedMachineIds: [...DEFAULT_UNLOCKED_MACHINE_IDS],
    machinePriorities: Object.fromEntries(
      Object.entries(DEFAULT_MACHINE_PRIORITIES).map(([key, ids]) => [
        key,
        [...ids],
      ]),
    ),
    processMachineChoices: {},
    machineQuality: "normal",
    machineModuleFamilies: [qualityMode ? "quality" : "productivity"],
    machineModuleTier: 3,
    machineModuleQuality: "normal",
    beaconEnabled: qualityMode,
    beaconMode: qualityMode ? "quality-safe" : "standard",
    beaconCount: qualityMode ? 1 : 0,
    beaconModuleFamily: "speed",
    beaconModuleTier: 3,
    beaconModuleQuality: "normal",
    beaconQuality: "normal",
    inserterId: DEFAULT_LOGISTICS.inserterId,
    inserterQuality: DEFAULT_LOGISTICS.inserterQuality,
    inserterCapacityBonus: DEFAULT_LOGISTICS.capacityBonus,
    inserterHandoff: DEFAULT_LOGISTICS.handoff,
  };
}

function copyChainMaster(master: ChainMasterSettings): ChainMasterSettings {
  return {
    ...master,
    unlockedMachineIds: [
      ...(master.unlockedMachineIds ?? DEFAULT_UNLOCKED_MACHINE_IDS),
    ],
    machinePriorities: Object.fromEntries(
      Object.entries(
        master.machinePriorities ?? DEFAULT_MACHINE_PRIORITIES,
      ).map(([key, ids]) => [
        key,
        [...ids],
      ]),
    ),
    processMachineChoices: { ...(master.processMachineChoices ?? {}) },
    machineModuleFamilies: [...master.machineModuleFamilies],
  };
}

function copyModuleConfig(config: ModuleConfig): ModuleConfig {
  return {
    ...config,
    families: [...config.families],
    manual: config.manual.map((slot) => (slot ? { ...slot } : null)),
  };
}

function clearOverridesForMasterPatch(
  overrides: Record<string, ChainOverride>,
  patch: Partial<ChainMasterSettings>,
): Record<string, ChainOverride> {
  const fields = new Set<keyof ChainOverride>();
  if (
    "preferredMachineId" in patch ||
    "processMachineChoices" in patch ||
    "unlockedMachineIds" in patch ||
    "machinePriorities" in patch
  ) {
    fields.add("recipeId");
    fields.add("machineId");
  }
  if ("machineQuality" in patch) fields.add("machineQuality");
  if ("machineModuleFamilies" in patch) {
    fields.add("machineModuleFamily");
    fields.add("machineModuleFamilies");
  }
  if ("machineModuleTier" in patch) fields.add("machineModuleTier");
  if ("machineModuleQuality" in patch) fields.add("machineModuleQuality");
  if ("beaconEnabled" in patch) fields.add("beaconEnabled");
  if ("beaconMode" in patch) fields.add("beaconMode");
  if ("beaconCount" in patch) fields.add("beaconCount");
  if ("beaconModuleFamily" in patch) fields.add("beaconModuleFamily");
  if ("beaconModuleTier" in patch) fields.add("beaconModuleTier");
  if ("beaconModuleQuality" in patch) fields.add("beaconModuleQuality");
  if ("beaconQuality" in patch) fields.add("beaconQuality");
  if ("inserterId" in patch) fields.add("inserterId");
  if ("inserterQuality" in patch) fields.add("inserterQuality");
  if ("inserterCapacityBonus" in patch) fields.add("inserterCapacityBonus");
  if ("inserterHandoff" in patch) fields.add("inserterHandoff");
  if (!fields.size) return overrides;
  return Object.fromEntries(
    Object.entries(overrides).map(([key, override]) => {
      const next = { ...override };
      for (const field of fields) delete next[field];
      return [key, next];
    }),
  );
}

function makeProductionTarget(
  id: string,
  qualityMode: boolean,
  productKey = DEFAULT_PRODUCT,
  amount = 60,
  template?: ProductionTargetState,
  globalMaster = makeChainMaster(qualityMode),
): ProductionTargetState {
  const product = PRODUCT_BY_KEY.get(productKey) ?? PRODUCTS[0];
  const defaultRecipe = qualityMode
    ? preferredChainRecipeForProduct(product)
    : preferredRecipeForProduct(product);
  const defaultMachines = rankedMachinesForRecipe(defaultRecipe, globalMaster);
  const inheritedMachine = template
    ? defaultMachines.find((candidate) => candidate.id === template.machineId)
    : undefined;
  const preferredRoute = inheritedMachine
    ? { recipe: defaultRecipe, machine: inheritedMachine }
    : defaultMachines[0]
      ? { recipe: defaultRecipe, machine: defaultMachines[0] }
      : preferredUnlockedChainRoute(product, globalMaster);
  const recipe = preferredRoute?.recipe ?? defaultRecipe;
  const machine = preferredRoute?.machine ?? preferredMachineForRecipe(recipe);
  const templateAmount = template?.amount ?? amount;
  const constraintCount = Math.min(
    recipe.ingredients.length,
    Math.max(1, template?.constraints.length ?? 1),
  );
  const constraints = recipe.ingredients
    .slice(0, constraintCount)
    .map((ingredient, index) => ({
      id: `c-${id}-${index}`,
      ingredientKey: `${ingredient.type}:${ingredient.name}`,
      amount: template?.constraints[index]?.amount ?? templateAmount,
    }));
  const machineConfig = template
    ? copyModuleConfig(template.machineConfig)
    : {
        mode: "auto" as const,
        families: [...globalMaster.machineModuleFamilies],
        tier: globalMaster.machineModuleTier,
        quality: globalMaster.machineModuleQuality,
        manual: [],
      };
  const beaconConfig = template
    ? copyModuleConfig(template.beaconConfig)
    : {
        mode: "auto" as const,
        families:
          globalMaster.beaconModuleFamily === "none"
            ? []
            : [globalMaster.beaconModuleFamily],
        tier: globalMaster.beaconModuleTier,
        quality: globalMaster.beaconModuleQuality,
        manual: [],
      };
  const qualitySafe = qualityMode && beaconConfig.mode === "auto";
  return {
    id,
    productKey: product.key,
    recipeId: recipe.id,
    machineId: machine.id,
    amount: templateAmount,
    unit: template?.unit ?? "s",
    rateMode: template?.rateMode ?? "output",
    constraints,
    machineQuality: template?.machineQuality ?? globalMaster.machineQuality,
    inputQuality: template?.inputQuality ?? "normal",
    outputQuality: template?.outputQuality ?? "total",
    maxQuality: template?.maxQuality ?? "legendary",
    machineConfig,
    beaconConfig,
    beaconCount: template
      ? Math.min(template.beaconCount, qualitySafe ? 1 : machine.maxBeacons)
      : globalMaster.beaconEnabled
      ? Math.min(
          qualitySafe ? 1 : globalMaster.beaconCount,
          machine.maxBeacons,
        )
      : 0,
    beaconQuality: template?.beaconQuality ?? globalMaster.beaconQuality,
    chainEnabled: template?.chainEnabled ?? true,
    showChain: false,
    resultCollapsed: false,
    chainMaster: copyChainMaster(globalMaster),
    chainOverrides: {},
    logistics: template
      ? { ...template.logistics }
      : {
          inserterId: globalMaster.inserterId,
          inserterQuality: globalMaster.inserterQuality,
          capacityBonus: globalMaster.inserterCapacityBonus,
          handoff: globalMaster.inserterHandoff,
        },
    blueprintSettings: template
      ? { ...template.blueprintSettings, nodeKey: undefined }
      : { ...DEFAULT_BLUEPRINT_BLOCK_SETTINGS },
    includeDirectEnergy: template?.includeDirectEnergy ?? !qualityMode,
    includeChainEnergy: template?.includeChainEnergy ?? false,
  };
}

function applyMasterToMainTarget(
  target: ProductionTargetState,
  master: ChainMasterSettings,
  patch: Partial<ChainMasterSettings>,
  qualityMode: boolean,
): ProductionTargetState {
  let next = { ...target };
  if (
    "preferredMachineId" in patch ||
    "unlockedMachineIds" in patch ||
    "machinePriorities" in patch
  ) {
    const currentRecipe = RECIPE_BY_ID.get(target.recipeId);
    const currentMachine = currentRecipe
      ? rankedMachinesForRecipe(currentRecipe, master)[0]
      : undefined;
    const product = PRODUCT_BY_KEY.get(target.productKey);
    const route =
      currentRecipe && currentMachine
        ? { recipe: currentRecipe, machine: currentMachine }
        : product
          ? preferredUnlockedChainRoute(product, master)
          : undefined;
    if (route) {
      next = {
        ...next,
        recipeId: route.recipe.id,
        machineId: route.machine.id,
        beaconCount: Math.min(next.beaconCount, route.machine.maxBeacons),
      };
    }
  }
  if ("machineQuality" in patch)
    next.machineQuality = master.machineQuality;
  if (
    "machineModuleFamilies" in patch ||
    "machineModuleTier" in patch ||
    "machineModuleQuality" in patch
  ) {
    next.machineConfig = {
      mode: "auto",
      families: [...master.machineModuleFamilies],
      tier: master.machineModuleTier,
      quality: master.machineModuleQuality,
      manual: [],
    };
  }
  if (
    "beaconEnabled" in patch ||
    "beaconMode" in patch ||
    "beaconCount" in patch ||
    "beaconModuleFamily" in patch ||
    "beaconModuleTier" in patch ||
    "beaconModuleQuality" in patch ||
    "beaconQuality" in patch
  ) {
    const machine = selectedEntities(next, qualityMode).machine;
    next.beaconConfig = {
      mode: "auto",
      families:
        master.beaconModuleFamily === "none"
          ? []
          : [master.beaconModuleFamily],
      tier: master.beaconModuleTier,
      quality: master.beaconModuleQuality,
      manual: [],
    };
    next.beaconCount = master.beaconEnabled
      ? Math.min(
          qualityMode && master.beaconMode === "quality-safe"
            ? 1
            : master.beaconCount,
          machine.maxBeacons,
        )
      : 0;
    next.beaconQuality = master.beaconQuality;
  }
  if (
    "inserterId" in patch ||
    "inserterQuality" in patch ||
    "inserterCapacityBonus" in patch ||
    "inserterHandoff" in patch
  ) {
    next.logistics = {
      inserterId: master.inserterId,
      inserterQuality: master.inserterQuality,
      capacityBonus: master.inserterCapacityBonus,
      handoff: master.inserterHandoff,
    };
  }
  return next;
}
function selectedEntities(
  target: ProductionTargetState,
  qualityMode = false,
) {
  const product = PRODUCT_BY_KEY.get(target.productKey) ?? PRODUCTS[0];
  const recipe =
    RECIPE_BY_ID.get(target.recipeId) ??
    (qualityMode
      ? preferredChainRecipeForProduct(product)
      : preferredRecipeForProduct(product));
  const unlocked = rankedMachinesForRecipe(recipe, target.chainMaster);
  const compatible = unlocked.length ? unlocked : machinesForRecipe(recipe);
  const machine =
    compatible.find((entry) => entry.id === target.machineId) ?? compatible[0];
  return { product, recipe, machine, compatible };
}
function buildInput(
  target: ProductionTargetState,
  qualityMode: boolean,
): CalculatorInput {
  const { product, recipe, machine } = selectedEntities(target, qualityMode);
  const safeQualityBeacon = qualityMode && target.beaconConfig.mode === "auto";
  const machineModules = resolvedModules(
    target.machineConfig,
    machine.moduleSlots,
    machine,
    recipe,
  );
  const beaconSlots = safeQualityBeacon ? 1 : 2;
  const resolvedBeacon = resolvedModules(
    target.beaconConfig,
    beaconSlots,
    machine,
    recipe,
    true,
  );
  const beaconModules = safeQualityBeacon
    ? [resolvedBeacon[0] ?? null, null]
    : resolvedBeacon;
  const calculatesQuality =
    qualityMode || machineModules.some((module) => module?.family === "quality");
  return {
    recipe,
    product,
    machine,
    machineQuality: target.machineQuality,
    inputQuality: target.inputQuality,
    outputQuality:
      qualityMode && product.type !== "fluid" ? target.outputQuality : "total",
    maxQuality: qualityMode ? target.maxQuality : "legendary",
    calculationMode: calculatesQuality ? "quality" : "normal",
    machineModules,
    beaconModules,
    beaconQuality: target.beaconQuality,
    beaconCount: Math.min(
      safeQualityBeacon ? Math.min(1, target.beaconCount) : target.beaconCount,
      machine.maxBeacons,
    ),
    mode: target.rateMode,
    amount: target.amount,
    unit: target.unit,
    inputConstraints: target.constraints,
  };
}

function ProductPicker({
  product,
  locale,
  onChange,
}: {
  product?: ProductOption;
  locale: Locale;
  onChange: (key: string) => void;
}) {
  const options = useMemo(
    () =>
      PRODUCTS.map((entry) => ({
        value: entry.key,
        label: localizedName(entry.id, locale, entry.type),
        icon: entry.icon,
        meta: entry.type === "fluid" ? tr(locale, "fluid") : undefined,
        keywords: `${entry.name} ${entry.id}`,
        group: entry.group,
        subgroup: entry.subgroup,
        subgroupLabel: entry.subgroup
          ? localizedName(entry.subgroup, locale, "subgroup")
          : undefined,
      })),
    [locale],
  );
  const groups: SearchPickerGroup[] = useMemo(
    () =>
      GROUPS.map((id) => ({
        id,
        label: groupLabel(id, locale),
        icon: iconForGroup(id),
      })),
    [locale],
  );
  return (
    <SearchPicker
      value={product?.key ?? ""}
      options={options}
      groups={groups}
      onChange={onChange}
      placeholder={tr(locale, "selectProduct")}
      searchPlaceholder={tr(locale, "searchProducts")}
      emptyText={tr(locale, "noMatch")}
    />
  );
}

function OutputMaterialPicker({
  flow,
  unit,
  locale,
  onNavigate,
}: {
  flow: MaterialFlow;
  unit: RateUnit;
  locale: Locale;
  onNavigate: (productKey: string, rate: number) => void;
}) {
  const productKey = `${flow.type}:${flow.id}`;
  const current = PRODUCT_BY_KEY.get(productKey);
  const nextProducts = downstreamProducts(productKey);
  if (!nextProducts.length)
    return <MaterialRow flow={flow} unit={unit} locale={locale} />;
  const options = nextProducts.map((product) => ({
    value: product.key,
    label: localizedName(product.id, locale, product.type),
    icon: product.icon,
    meta: product.type === "fluid" ? tr(locale, "fluid") : undefined,
    keywords: `${product.name} ${product.id}`,
    group: product.group,
    subgroup: product.subgroup,
    subgroupLabel: product.subgroup
      ? localizedName(product.subgroup, locale, "subgroup")
      : undefined,
  }));
  const groups: SearchPickerGroup[] = GROUPS.filter((group) =>
    nextProducts.some((product) => product.group === group),
  ).map((id) => ({
    id,
    label: groupLabel(id, locale),
    icon: iconForGroup(id),
  }));
  return (
    <SearchPicker
      value={productKey}
      options={options}
      groups={groups}
      triggerOption={{
        value: productKey,
        label: localizedName(flow.id, locale, flow.type),
        icon: flow.icon,
        group: current?.group,
        subgroup: current?.subgroup,
      }}
      triggerContent={
        <MaterialRowContent flow={flow} unit={unit} locale={locale} />
      }
      onChange={(nextKey) =>
        onNavigate(nextKey, toDisplayRate(flow.total, unit))
      }
      placeholder={tr(locale, "chooseNextProduct")}
      searchPlaceholder={tr(locale, "downstreamProducts")}
      emptyText={tr(locale, "noMatch")}
      triggerClassName="border-white/7 bg-[#151719] text-zinc-100 hover:border-[#f7a72d]/40 hover:bg-[#191c1e]"
    />
  );
}

function ProductionTargetSettings({
  target,
  qualityMode,
  locale,
  onChange,
  onRemove,
  onActivate,
  canRemove,
  tone,
}: {
  target: ProductionTargetState;
  qualityMode: boolean;
  locale: Locale;
  onChange: (patch: Partial<ProductionTargetState>) => void;
  onRemove: () => void;
  onActivate: () => void;
  canRemove: boolean;
  tone: number;
}) {
  const { product, recipe, machine, compatible } = selectedEntities(
    target,
    qualityMode,
  );
  const routes = product.recipeIds
    .map((id) => RECIPE_BY_ID.get(id))
    .filter((entry): entry is Recipe => Boolean(entry));
  const inputOptions = recipe.ingredients.map((ingredient) => ({
    key: `${ingredient.type}:${ingredient.name}`,
    id: ingredient.name,
    type: ingredient.type,
  }));
  const safeQualityBeacon = qualityMode && target.beaconConfig.mode === "auto";
  const machineIcons = [
    "assembling-machine-3",
    "electromagnetic-plant",
    "foundry",
    "chemical-plant",
    "cryogenic-plant",
    "biochamber",
    "recycler",
  ].map((id) => iconFor(id));
  const moduleIcons = (
    ["productivity", "speed", "quality", "efficiency"] as ModuleFamily[]
  ).map((f) => iconFor(`${f}-module-3`));
  const reconcileConstraints = (nextRecipe: Recipe): InputConstraint[] => {
    const available = nextRecipe.ingredients.map(
      (ingredient) => `${ingredient.type}:${ingredient.name}`,
    );
    if (!available.length) return [];
    const previous = target.constraints.length
      ? target.constraints
      : [{ id: `c-${target.id}`, ingredientKey: "", amount: 60 }];
    return previous.slice(0, available.length).map((constraint, index) => {
      const preferredIndex = available.indexOf(constraint.ingredientKey);
      const ingredientKey =
        preferredIndex >= 0
          ? available.splice(preferredIndex, 1)[0]
          : available.shift()!;
      return {
        ...constraint,
        ingredientKey,
        id: constraint.id || `c-${target.id}-${index}`,
      };
    });
  };
  const chooseProduct = (key: string) => {
    const nextProduct = PRODUCT_BY_KEY.get(key)!;
    const nextRecipe = qualityMode
      ? preferredChainRecipeForProduct(nextProduct)
      : preferredRecipeForProduct(nextProduct);
    const nextMachine =
      rankedMachinesForRecipe(nextRecipe, target.chainMaster)[0] ??
      preferredMachineForRecipe(nextRecipe);
    onChange({
      productKey: key,
      recipeId: nextRecipe.id,
      machineId: nextMachine.id,
      beaconCount: Math.min(target.beaconCount, nextMachine.maxBeacons),
      constraints: reconcileConstraints(nextRecipe),
    });
  };
  const chooseRecipe = (id: string) => {
    const nextRecipe = RECIPE_BY_ID.get(id)!;
    const nextMachine =
      rankedMachinesForRecipe(nextRecipe, target.chainMaster)[0] ??
      preferredMachineForRecipe(nextRecipe);
    onChange({
      recipeId: id,
      machineId: nextMachine.id,
      beaconCount: Math.min(target.beaconCount, nextMachine.maxBeacons),
      constraints: reconcileConstraints(nextRecipe),
    });
  };
  return (
    <CollapsiblePanel
      className="product-scope collapsible-panel group rounded-2xl border bg-[#0f1113]"
      data-product-tone={tone}
      onClick={onActivate}
      defaultOpen
    >
      <summary className="collapsible-summary list-none p-4">
        <span className="summary-leading flex min-w-0 items-center gap-3">
          <FactorioIcon src={product.icon} alt="" size="lg" />
          <span className="min-w-0 flex-1">
            <strong className="block whitespace-normal break-words text-sm">
              {localizedName(product.id, locale, product.type)}
            </strong>
            <small className="font-mono text-[9px] text-zinc-600">
              {localizedName(machine.id, locale, "entity")}
            </small>
          </span>
        </span>
        <span className="summary-trailing">
          <span className="summary-kpi" data-kpi-tone="orange">
            <small>{tr(locale, "targetRate")}</small>
            <strong>
              {formatNumber(target.amount, locale)} {unitLabel(target.unit)}
            </strong>
          </span>
          <Button
            type="button"
            size="icon-sm"
            variant="ghost"
            disabled={!canRemove}
            onClick={(event) => {
              event.preventDefault();
              event.stopPropagation();
              onRemove();
            }}
            className="text-zinc-600 hover:text-[#e65d4f]"
          >
            <Trash2 />
          </Button>
          <ChevronDown className="details-chevron size-4 text-zinc-600 transition" />
        </span>
      </summary>
      <div className="space-y-3 border-t border-white/7 p-3">
        <ExpandableSection
          number="01"
          title={tr(locale, "productRoute")}
        >
          <FieldLabel detail={`${PRODUCTS.length} ${tr(locale, "available")}`}>
            {tr(locale, "product")}
          </FieldLabel>
          <ProductPicker
            product={product}
            locale={locale}
            onChange={chooseProduct}
          />
          <div className="mt-3">
            <FieldLabel detail={`${routes.length} ${tr(locale, "route")}`}>
              {tr(locale, "recipeRoute")}
            </FieldLabel>
            <Select value={recipe.id} onValueChange={chooseRecipe}>
              <SelectTrigger className={selectClass}>
                <SelectValue />
              </SelectTrigger>
              <SelectContent className="max-h-80">
                {routes.map((route) => (
                  <SelectItem key={route.id} value={route.id}>
                    <span className="flex items-center gap-2">
                      <FactorioIcon src={route.icon} alt="" size="sm" />
                      {localizedName(route.id, locale, "recipe")}
                    </span>
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
        </ExpandableSection>
        <ExpandableSection
          number="02"
          title={tr(locale, "productionMachine")}
          icons={machineIcons}
        >
          <div className="grid grid-cols-2 gap-2">
            {compatible.map((option) => (
              <button
                type="button"
                key={option.id}
                onClick={() =>
                  onChange({
                    machineId: option.id,
                    beaconCount: Math.min(
                      target.beaconCount,
                      option.maxBeacons,
                    ),
                  })
                }
                className={`flex min-w-0 items-center gap-2 rounded-xl border p-2.5 text-left ${option.id === machine.id ? "border-[#f7a72d]/55 bg-[#f7a72d]/10" : "border-white/8 bg-[#17191b]"}`}
              >
                <FactorioIcon src={option.icon} alt="" size="lg" />
                <span className="min-w-0">
                  <span className="block truncate text-xs">
                    {localizedName(option.id, locale, "entity")}
                  </span>
                  <span className="block font-mono text-[9px] text-zinc-600">
                    {option.speed}× · {option.moduleSlots} {tr(locale, "slots")}
                  </span>
                </span>
              </button>
            ))}
          </div>
          <div className="mt-3 grid grid-cols-2 gap-2">
            <div>
              <FieldLabel>{tr(locale, "machineQuality")}</FieldLabel>
              <QualitySelect
                value={target.machineQuality}
                onChange={(v) => onChange({ machineQuality: v as QualityId })}
                locale={locale}
              />
            </div>
            <div>
              <FieldLabel>{tr(locale, "ingredientQuality")}</FieldLabel>
              <QualitySelect
                value={target.inputQuality}
                onChange={(v) => onChange({ inputQuality: v as QualityId })}
                locale={locale}
              />
            </div>
          </div>
          {qualityMode ? (
            <div className="mt-3">
              <FieldLabel>{tr(locale, "maximumQuality")}</FieldLabel>
              <QualitySelect
                value={target.maxQuality}
                onChange={(v) => onChange({ maxQuality: v as QualityId })}
                locale={locale}
              />
            </div>
          ) : null}
        </ExpandableSection>
        <ExpandableSection
          number="03"
          title={tr(locale, "targetRate")}
          icons={["/factorio-icons/base/icons/arrows/up-arrow.png"]}
          className="target-rate-focus"
        >
          <div className="mb-3 grid grid-cols-2 rounded-lg border border-white/8 bg-[#17191b] p-1">
            {(["output", "input"] as const).map((mode) => (
              <button
                type="button"
                key={mode}
                onClick={() => onChange({ rateMode: mode })}
                className={`rounded py-2 text-xs ${target.rateMode === mode ? "bg-[#303439] text-[#f7a72d]" : "text-zinc-500"}`}
              >
                {tr(
                  locale,
                  mode === "output" ? "desiredOutput" : "inputLimited",
                )}
              </button>
            ))}
          </div>
          {target.rateMode === "output" ? (
            <div className="grid grid-cols-[1fr_88px] gap-2">
              <div>
                <FieldLabel>{tr(locale, "amount")}</FieldLabel>
                <SmartNumberInput
                  min={0}
                  step={1}
                  value={target.amount}
                  onValueChange={(amount) => onChange({ amount })}
                />
              </div>
              <div>
                <FieldLabel>{tr(locale, "unit")}</FieldLabel>
                <UnitSelect
                  value={target.unit}
                  onChange={(unit) => onChange({ unit })}
                />
              </div>
            </div>
          ) : (
            <div className="space-y-2">
              {target.constraints.map((constraint) => (
                <div
                  key={constraint.id}
                  className="grid grid-cols-[1fr_92px_28px] gap-2"
                >
                  <Select
                    value={constraint.ingredientKey}
                    onValueChange={(ingredientKey) =>
                      onChange({
                        constraints: target.constraints.map((c) =>
                          c.id === constraint.id ? { ...c, ingredientKey } : c,
                        ),
                      })
                    }
                  >
                    <SelectTrigger className={selectClass}>
                      <SelectValue />
                    </SelectTrigger>
                    <SelectContent>
                      {inputOptions.map((entry) => (
                        <SelectItem key={entry.key} value={entry.key}>
                          <span className="flex items-center gap-2">
                            <FactorioIcon
                              src={iconFor(entry.id, entry.type)}
                              alt=""
                              size="sm"
                            />
                            {localizedName(entry.id, locale, entry.type)}
                          </span>
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                  <SmartNumberInput
                    min={0}
                    value={constraint.amount}
                    onValueChange={(amount) =>
                      onChange({
                        constraints: target.constraints.map((c) =>
                          c.id === constraint.id ? { ...c, amount } : c,
                        ),
                      })
                    }
                  />
                  <Button
                    type="button"
                    size="icon-sm"
                    variant="ghost"
                    disabled={target.constraints.length <= 1}
                    onClick={() =>
                      onChange({
                        constraints: target.constraints.filter(
                          (c) => c.id !== constraint.id,
                        ),
                      })
                    }
                  >
                    <Trash2 />
                  </Button>
                </div>
              ))}
              <div className="flex gap-2">
                <Button
                  type="button"
                  variant="outline"
                  size="sm"
                  onClick={() => {
                    const used = new Set(
                      target.constraints.map((c) => c.ingredientKey),
                    );
                    const next = inputOptions.find(
                      (entry) => !used.has(entry.key),
                    );
                    if (next)
                      onChange({
                        constraints: [
                          ...target.constraints,
                          {
                            id: `c-${Date.now()}`,
                            ingredientKey: next.key,
                            amount: 60,
                          },
                        ],
                      });
                  }}
                >
                  <Plus />
                  {tr(locale, "addInput")}
                </Button>
                <UnitSelect
                  value={target.unit}
                  onChange={(unit) => onChange({ unit })}
                />
              </div>
            </div>
          )}
          {qualityMode ? (
            <div className="mt-3">
              <FieldLabel>{tr(locale, "targetQuality")}</FieldLabel>
              <QualitySelect
                value={product.type === "fluid" ? "total" : target.outputQuality}
                onChange={(v) => onChange({ outputQuality: v })}
                locale={locale}
                includeTotal
                disabled={product.type === "fluid"}
                maxQuality={target.maxQuality}
              />
            </div>
          ) : null}
        </ExpandableSection>
        <ExpandableSection
          number="04"
          title={tr(locale, "modules")}
          icons={moduleIcons}
          open={false}
        >
          <ModuleConfigurator
            title={tr(locale, "machineModules")}
            locale={locale}
            slots={machine.moduleSlots}
            machine={machine}
            recipe={recipe}
            config={target.machineConfig}
            onChange={(machineConfig) => onChange({ machineConfig })}
            allowedFamilies={["productivity", "speed", "quality", "efficiency"]}
            autoAllowedFamilies={
              qualityMode
                ? ["quality"]
                : ["productivity", "speed", "quality", "efficiency"]
            }
          />
        </ExpandableSection>
        <ExpandableSection
          number="05"
          title={tr(locale, "beacons")}
          icons={[iconFor("beacon")]}
          open={false}
        >
          {machine.maxBeacons ? (
            <>
              <div className="grid grid-cols-2 gap-2">
                <div>
                  <FieldLabel
                    detail={`max ${safeQualityBeacon ? 1 : machine.maxBeacons}`}
                  >
                    {tr(locale, "activePerMachine")}
                  </FieldLabel>
                  <BeaconCountSelect
                    value={target.beaconCount}
                    maximum={safeQualityBeacon ? 1 : machine.maxBeacons}
                    onChange={(beaconCount) => onChange({ beaconCount })}
                  />
                </div>
                <div>
                  <FieldLabel>{tr(locale, "beaconQuality")}</FieldLabel>
                  <QualitySelect
                    value={target.beaconQuality}
                    onChange={(v) =>
                      onChange({ beaconQuality: v as QualityId })
                    }
                    locale={locale}
                  />
                </div>
              </div>
              {safeQualityBeacon ? (
                <div className="notice-info">
                  {tr(locale, "qualitySafeBeacon")}
                </div>
              ) : null}
              <ModuleConfigurator
                title={tr(locale, "beaconModules")}
                locale={locale}
                slots={safeQualityBeacon ? 1 : 2}
                machine={machine}
                recipe={recipe}
                beacon
                config={target.beaconConfig}
                onChange={(beaconConfig) => onChange({ beaconConfig })}
                allowedFamilies={["speed", "efficiency"]}
              />
            </>
          ) : (
            <p className="text-xs text-zinc-500">
              {localizedName(machine.id, locale, "entity")}: 0{" "}
              {tr(locale, "beacons")}
            </p>
          )}
        </ExpandableSection>
        <button
          type="button"
          onClick={() =>
            onChange({
              machineQuality: "normal",
              inputQuality: "normal",
              outputQuality: "total",
              maxQuality: "legendary",
              machineConfig: {
                mode: "auto",
                families: [qualityMode ? "quality" : "productivity"],
                tier: 3,
                quality: "normal",
                manual: [],
              },
              beaconConfig: {
                mode: "auto",
                families: ["speed"],
                tier: 3,
                quality: "normal",
                manual: [],
              },
              beaconCount: qualityMode ? 1 : 0,
              beaconQuality: "normal",
            })
          }
          className="flex w-full items-center justify-center gap-2 rounded-xl border border-white/7 py-2.5 text-xs text-zinc-600 hover:text-zinc-300"
        >
          <RotateCcw className="size-3.5" />
          {tr(locale, "reset")}
        </button>
      </div>
    </CollapsiblePanel>
  );
}

type ComputedTarget = {
  target: ProductionTargetState;
  input: CalculatorInput;
  result: ReturnType<typeof calculate>;
  logisticsResult: ReturnType<typeof calculateLogistics>;
  chain?: ReturnType<typeof buildProductionChain>;
};
function ProductionTargetResult({
  computed,
  qualityMode,
  locale,
  onChange,
  onNavigate,
  energySelection,
  onEnergyToggle,
  tone,
}: {
  computed: ComputedTarget;
  qualityMode: boolean;
  locale: Locale;
  onChange: (patch: Partial<ProductionTargetState>) => void;
  onNavigate: (productKey: string, rate: number) => void;
  energySelection?: EnergySourceSelection;
  onEnergyToggle: (
    id: string,
    field: "includeDirect" | "includeChain",
    value: boolean,
  ) => void;
  tone: number;
}) {
  const { target, input, result, logisticsResult, chain } = computed;
  if (!result.valid)
    return (
      <article className="rounded-2xl border border-white/9 bg-[#111315] p-8 text-center">
        <AlertTriangle className="mx-auto mb-3 size-9 text-[#e65d4f]" />
        <h2 className="text-lg font-semibold">{tr(locale, "invalidSetup")}</h2>
        <p className="mt-2 text-sm text-zinc-500">
          {localizeCoreMessage(result.message, locale)}
        </p>
      </article>
    );
  const isolatedBuild =
    result.cyclesPerSecond > 0
      ? Math.max(1, Math.ceil(result.theoreticalMachines - 1e-12))
      : 0;
  const nextProducts = downstreamProducts(input.product.key);
  const nextOptions = nextProducts.map((product) => ({
    value: product.key,
    label: localizedName(product.id, locale, product.type),
    icon: product.icon,
    meta: product.type === "fluid" ? tr(locale, "fluid") : undefined,
    keywords: `${product.name} ${product.id}`,
    group: product.group,
    subgroup: product.subgroup,
    subgroupLabel: product.subgroup
      ? localizedName(product.subgroup, locale, "subgroup")
      : undefined,
  }));
  const nextGroups: SearchPickerGroup[] = GROUPS.filter((group) =>
    nextProducts.some((product) => product.group === group),
  ).map((id) => ({
    id,
    label: groupLabel(id, locale),
    icon: iconForGroup(id),
  }));
  const ignoredMachine = input.machineModules.filter(
    (module) => module && !moduleIsAllowed(module, input.machine, input.recipe),
  ).length;
  const ignoredBeacon = input.beaconModules.filter(
    (module) =>
      module && !moduleIsAllowed(module, input.machine, input.recipe, true),
  ).length;
  const localizedWarnings = new Set<string>();
  if (ignoredMachine)
    localizedWarnings.add(
      `${tr(locale, "warnings")} · ${ignoredMachine} × ${tr(locale, "machineModules")}`,
    );
  if (ignoredBeacon)
    localizedWarnings.add(
      `${tr(locale, "warnings")} · ${ignoredBeacon} × ${tr(locale, "beaconModules")}`,
    );
  if (
    !input.isolatedBeacons &&
    input.beaconCount > 0 &&
    result.machinesToBuild > 1
  )
    localizedWarnings.add(
      `${tr(locale, "geometryCheck")} · Ø ${formatNumber(result.beaconLayout.average, locale, 2)} ${tr(locale, "beacons")} (${result.beaconLayout.min}–${result.beaconLayout.max})`,
    );
  if (result.machinesToBuild > isolatedBuild)
    localizedWarnings.add(
      `${tr(locale, "machinesRequired")}: ${isolatedBuild} → ${result.machinesToBuild}`,
    );
  if (
    result.qualityChance > 0 ||
    input.recipe.products.some((product) => product.probability < 1)
  )
    localizedWarnings.add(
      `${tr(locale, "expectedOutputs")} · ${tr(locale, "theoretical")}`,
    );
  if (
    1 + result.machineEffects.speed + result.isolatedBeaconEffects.speed <=
    0.2000001
  )
    localizedWarnings.add(`${tr(locale, "craftingSpeed")} ≥ 20%`);
  if (input.machine.auxiliaryActiveKw)
    localizedWarnings.add(
      `${localizedName(input.machine.id, locale, "entity")} · +${formatPower(input.machine.auxiliaryActiveKw, locale)}`,
    );
  if (target.resultCollapsed)
    return (
      <article
        className="product-scope hierarchy-panel overflow-hidden rounded-2xl border bg-[#111315] shadow-[0_20px_70px_rgba(0,0,0,.2)]"
        data-product-tone={tone}
      >
        <button
          type="button"
          onClick={() => onChange({ resultCollapsed: false })}
          className="collapsible-summary dashboard-summary w-full list-none p-5 text-left transition hover:bg-white/[.025]"
          title={tr(locale, "expandProductResult")}
          aria-label={tr(locale, "expandProductResult")}
        >
          <span className="summary-leading flex min-w-0 items-center gap-3">
            <FactorioIcon src={input.product.icon} alt="" size="lg" />
            <span className="min-w-0 flex-1">
              <strong className="block whitespace-normal break-words text-sm text-zinc-100">
                {localizedName(input.product.id, locale, input.product.type)}
              </strong>
              <span className="block whitespace-normal break-words text-[10px] text-zinc-600">
                {localizedName(input.recipe.id, locale, "recipe")} ·{" "}
                {localizedName(input.machine.id, locale, "entity")}
                {chain ? ` · ${tr(locale, "fullChain")}` : ""}
              </span>
            </span>
          </span>
          <span className="summary-trailing">
            <span className="summary-kpi" data-kpi-tone="cyan">
              <small>{tr(locale, "throughput")}</small>
              <strong>
                {formatNumber(
                  toDisplayRate(result.ratePerSecond, target.unit),
                  locale,
                )}
                {unitLabel(target.unit)}
              </strong>
            </span>
            <ChevronDown className="details-chevron size-4 shrink-0 text-[#69c5df]" />
          </span>
        </button>
      </article>
    );
  return (
    <article
      className="product-scope hierarchy-panel overflow-hidden rounded-2xl border bg-[#111315] shadow-[0_20px_70px_rgba(0,0,0,.2)]"
      data-product-tone={tone}
    >
      <div
        className="result-hero collapsible-summary dashboard-summary dashboard-result-header"
        onClick={(event) => {
          const interactive = (event.target as HTMLElement).closest(
            "button, input, select, textarea, a, [role='button'], [role='combobox'], [role='listbox']",
          );
          if (!interactive) onChange({ resultCollapsed: true });
        }}
      >
        <div className="summary-leading min-w-0">
          <div className="min-w-0">
            <p className="eyebrow">
              {qualityMode
                ? tr(locale, "qualityProduction")
                : tr(locale, "normalQuality")}
            </p>
            <SearchPicker
              value={input.product.key}
              options={nextOptions}
              groups={nextGroups}
              triggerOption={{
                value: input.product.key,
                label: localizedName(
                  input.product.id,
                  locale,
                  input.product.type,
                ),
                icon: input.product.icon,
                group: input.product.group,
              }}
              onChange={(productKey) => onNavigate(productKey, target.amount)}
              placeholder={tr(locale, "chooseNextProduct")}
              searchPlaceholder={tr(locale, "downstreamProducts")}
              emptyText={tr(locale, "noMatch")}
              triggerClassName="mt-1 h-14 max-w-xl border-[#69c5df]/20 bg-[#69c5df]/5 text-2xl font-semibold"
            />
            <p className="truncate text-xs text-zinc-500">
              {localizedName(input.recipe.id, locale, "recipe")} ·{" "}
              {localizedName(input.machine.id, locale, "entity")}
            </p>
          </div>
        </div>
        <div className="summary-trailing">
          <div className="summary-kpi summary-kpi-large" data-kpi-tone="cyan">
            <small>{tr(locale, "throughput")}</small>
            <strong>
              {formatNumber(
                toDisplayRate(result.ratePerSecond, target.unit),
                locale,
              )}
              {unitLabel(target.unit)}
            </strong>
          </div>
          <button
            type="button"
            onClick={() => onChange({ resultCollapsed: true })}
            className="flex size-4 shrink-0 items-center justify-center text-zinc-500 transition hover:text-[#a8e8f7]"
            title={tr(locale, "collapseProductResult")}
            aria-label={tr(locale, "collapseProductResult")}
          >
            <ChevronDown className="details-chevron size-4 rotate-180" />
          </button>
        </div>
      </div>
      <div className="product-result-body space-y-4 p-5">
      <div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-4">
        <MetricCard
          icon={<Factory className="size-4" />}
          label={tr(locale, "machinesRequired")}
          value={String(result.machinesToBuild)}
          detail={`${formatNumber(result.theoreticalMachines, locale)} ${tr(locale, "theoretical")}`}
        />
        <MetricCard
          icon={<CircleGauge className="size-4" />}
          label={tr(locale, "utilization")}
          value={`${formatNumber(result.utilization * 100, locale)}%`}
        />
        <MetricCard
          icon={<Gauge className="size-4" />}
          label={tr(locale, "craftingSpeed")}
          value={formatNumber(result.craftingSpeed, locale)}
        />
        <MetricCard
          icon={<Zap className="size-4" />}
          label={tr(locale, "power")}
          value={formatPower(
            result.electricTargetKw + logisticsResult.electricKw,
            locale,
          )}
          detail={`${formatPower(logisticsResult.electricKw, locale)} · ${tr(locale, "logistics")}`}
        />
      </div>
      <div className="grid gap-3 lg:grid-cols-2">
        <div>
          <h3 className="mb-2 text-sm font-semibold">
            {tr(locale, "ingredients")}
          </h3>
          <div className="space-y-2">
            {result.inputs.map((flow) => (
              <MaterialRow
                key={`${flow.type}:${flow.id}`}
                flow={flow}
                unit={target.unit}
                locale={locale}
                onClick={() => {
                  const key = `${flow.type}:${flow.id}`;
                  if (PRODUCT_BY_KEY.has(key))
                    onNavigate(key, toDisplayRate(flow.total, target.unit));
                }}
              />
            ))}
          </div>
        </div>
        <div>
          <h3 className="mb-2 text-sm font-semibold">
            {tr(locale, "outputs")}
          </h3>
          <div className="space-y-2">
            {result.outputs.map((flow) => (
              <OutputMaterialPicker
                key={`${flow.type}:${flow.id}`}
                flow={flow}
                unit={target.unit}
                locale={locale}
                onNavigate={onNavigate}
              />
            ))}
          </div>
        </div>
      </div>
      <div className="grid gap-2 sm:grid-cols-2">
        <label className="flex items-center justify-between rounded-lg border border-white/8 bg-[#17191b] p-3 text-xs">
          <span>
            <strong className="block">{tr(locale, "directPower")}</strong>
            <span className="text-zinc-600">
              {formatPower(
                result.electricTargetKw + logisticsResult.electricKw,
                locale,
              )}
            </span>
          </span>
          <input
            type="checkbox"
            checked={
              energySelection?.includeDirect ?? target.includeDirectEnergy
            }
            onChange={(e) => {
              onChange({ includeDirectEnergy: e.target.checked });
              onEnergyToggle(target.id, "includeDirect", e.target.checked);
            }}
          />
        </label>
        <label className="flex items-center justify-between rounded-lg border border-white/8 bg-[#17191b] p-3 text-xs">
          <span>
            <strong className="block">{tr(locale, "chainPower")}</strong>
            <span className="text-zinc-600">
              {chain
                ? formatPower(
                    Math.max(
                      0,
                      chain.includedElectricKw - chain.root.electricKw,
                    ),
                    locale,
                  )
                : "—"}
            </span>
          </span>
          <input
            type="checkbox"
            checked={energySelection?.includeChain ?? target.includeChainEnergy}
            disabled={!chain}
            onChange={(e) => {
              onChange({ includeChainEnergy: e.target.checked });
              onEnergyToggle(target.id, "includeChain", e.target.checked);
            }}
          />
        </label>
      </div>
      <LogisticsPanel
        result={logisticsResult}
        settings={target.logistics}
        onChange={(logistics) => onChange({ logistics })}
        locale={locale}
      />
      <ProductionGeometry
        input={input}
        result={result}
        logistics={logisticsResult}
        logisticsSettings={target.logistics}
        chain={chain}
        settings={target.blueprintSettings}
        onChange={(blueprintSettings) => onChange({ blueprintSettings })}
        locale={locale}
      />
      <div className="grid gap-2 sm:grid-cols-[minmax(0,1fr)_minmax(0,1.35fr)]">
        <label className="flex min-h-14 cursor-pointer items-center justify-between gap-3 rounded-xl border-2 border-[#74b768]/35 bg-[#74b768]/8 px-4 py-3 text-xs transition hover:border-[#74b768]/55">
          <span>
            <strong className="block text-[#b9e2b3]">
              {tr(locale, "includeProductionChain")}
            </strong>
            <span className="mt-0.5 block text-[10px] leading-snug text-zinc-500">
              {tr(locale, "includeProductionChainHint")}
            </span>
          </span>
          <input
            type="checkbox"
            checked={target.chainEnabled}
            onChange={(event) =>
              onChange({
                chainEnabled: event.target.checked,
                ...(!event.target.checked ? { showChain: false } : {}),
              })
            }
          />
        </label>
        <Button
          type="button"
          variant="outline"
          disabled={!target.chainEnabled}
          onClick={() => onChange({ showChain: !target.showChain })}
          className="h-14 w-full border-2 border-[#69c5df]/55 bg-[#69c5df]/12 text-sm font-semibold text-[#a8e8f7] shadow-[0_0_22px_rgba(105,197,223,.09)] hover:bg-[#69c5df]/18 disabled:cursor-not-allowed disabled:opacity-40"
        >
          {target.showChain ? tr(locale, "hideChain") : tr(locale, "showChain")}
          <ChevronDown
            className={`size-4 transition ${target.showChain ? "rotate-180" : ""}`}
          />
        </Button>
      </div>
      {chain && target.showChain ? (
        <ProductionChainPanel
          chain={chain}
          locale={locale}
          overrides={target.chainOverrides}
          master={target.chainMaster}
          qualityMode={qualityMode}
          onMaster={(patch) =>
            onChange({
              chainMaster: copyChainMaster({
                ...target.chainMaster,
                ...patch,
              }),
              chainOverrides: clearOverridesForMasterPatch(
                target.chainOverrides,
                patch,
              ),
            })
          }
          onOverride={(key, patch) =>
            onChange({
              chainOverrides: {
                ...target.chainOverrides,
                [key]: { ...(target.chainOverrides[key] ?? {}), ...patch },
              },
            })
          }
        />
      ) : null}
      {[...localizedWarnings].map((warning, index) => (
        <div key={index} className="notice-warning">
          <AlertTriangle className="size-4 shrink-0" />
          {warning}
        </div>
      ))}
      </div>
    </article>
  );
}

function ProductionModeWorkspace({
  locale,
  qualityMode,
  onEnergySources,
  energySelections,
  onEnergyToggle,
}: {
  locale: Locale;
  qualityMode: boolean;
  onEnergySources: (sources: EnergySourceSelection[]) => void;
  energySelections: Record<string, EnergySourceSelection>;
  onEnergyToggle: (
    id: string,
    field: "includeDirect" | "includeChain",
    value: boolean,
  ) => void;
}) {
  const prefix = qualityMode ? "q" : "p";
  const [targets, setTargets] = useState<ProductionTargetState[]>([]);
  const [activeTargetId, setActiveTargetId] = useState<string | null>(null);
  const [globalChainMaster, setGlobalChainMaster] =
    useState<ChainMasterSettings>(() => makeChainMaster(qualityMode));
  const computed = useMemo<ComputedTarget[]>(
    () =>
      targets.map((target) => {
        const baseInput = buildInput(target, qualityMode);
        const baseResult = calculate(baseInput);
        const chain =
          target.chainEnabled && baseResult.valid
            ? buildProductionChain({
                rootInput: baseInput,
                rootResult: baseResult,
                overrides: target.chainOverrides,
                masterSettings: target.chainMaster,
                logisticsSettings: target.logistics,
              })
            : undefined;
        const input = chain?.rootInput ?? baseInput;
        const result = chain?.rootResult ?? baseResult;
        const logisticsResult = calculateLogistics(
          result,
          input,
          target.logistics,
        );
        return { target, input, result, logisticsResult, chain };
      }),
    [targets, qualityMode],
  );
  const activeChains = useMemo(
    () => computed.flatMap((entry) => (entry.chain ? [entry.chain] : [])),
    [computed],
  );
  const factorySnapshots = useMemo(
    () =>
      computed.map(({ target, input, result, logisticsResult, chain }) => ({
        id: target.id,
        product: input.product,
        input,
        result,
        chain,
        logisticsSettings: target.logistics,
        logisticsResult,
        ...(BLUEPRINT_GENERATOR_ENABLED
          ? { beltSettings: target.blueprintSettings }
          : {}),
      })),
    [computed],
  );
  useEffect(() => {
    onEnergySources(
      computed.map(({ target, input, result, logisticsResult, chain }) => ({
        id: target.id,
        label: localizedName(input.product.id, locale, input.product.type),
        icon: input.product.icon,
        directKw: result.electricTargetKw + logisticsResult.electricKw,
        chainKw: chain
          ? Math.max(0, chain.includedElectricKw - chain.root.electricKw)
          : 0,
        includeDirect: target.includeDirectEnergy,
        includeChain: target.includeChainEnergy,
        mode: qualityMode ? "quality" : "production",
      })),
    );
  }, [computed, locale, onEnergySources, qualityMode]);
  const update = (id: string, patch: Partial<ProductionTargetState>) => {
    setActiveTargetId(id);
    setTargets((items) =>
      items.map((item) => (item.id === id ? { ...item, ...patch } : item)),
    );
  };
  const remove = (id: string) => {
    setTargets((items) => items.filter((item) => item.id !== id));
    if (activeTargetId === id) setActiveTargetId(null);
  };
  const promote = (id: string) => {
    setActiveTargetId(id);
    setTargets((items) => {
      const index = items.findIndex((item) => item.id === id);
      if (index <= 0) return items;
      return [items[index], ...items.slice(0, index), ...items.slice(index + 1)];
    });
  };
  const applyGlobalChainMaster = (patch: Partial<ChainMasterSettings>) => {
    const nextMaster = { ...globalChainMaster, ...patch };
    setGlobalChainMaster(nextMaster);
    setTargets((items) =>
      items.map((target) => {
        const mainTarget = applyMasterToMainTarget(
          target,
          nextMaster,
          patch,
          qualityMode,
        );
        return {
          ...mainTarget,
          chainMaster: copyChainMaster({
            ...target.chainMaster,
            ...patch,
          }),
          chainOverrides: clearOverridesForMasterPatch(
            target.chainOverrides,
            patch,
          ),
        };
      }),
    );
  };
  const add = (productKey: string, amount?: number) => {
    const id = `${prefix}-${Date.now()}`;
    setActiveTargetId(id);
    setTargets((items) => {
      const template =
        items.find((item) => item.id === activeTargetId) ?? items.at(-1);
      const next = makeProductionTarget(
        id,
        qualityMode,
        productKey,
        amount ?? template?.amount ?? 60,
        template,
        globalChainMaster,
      );
      return [...items, next];
    });
  };
  const navigate = (id: string, productKey: string, amount: number) => {
    setActiveTargetId(id);
    setTargets((items) =>
      items.map((target) => {
        if (target.id !== id) return target;
        const product = PRODUCT_BY_KEY.get(productKey);
        if (!product) return target;
        const recipe = qualityMode
          ? preferredChainRecipeForProduct(product)
          : preferredRecipeForProduct(product);
        const machine =
          rankedMachinesForRecipe(recipe, target.chainMaster)[0] ??
          preferredMachineForRecipe(recipe);
        const first = recipe.ingredients[0];
        return {
          ...target,
          productKey,
          recipeId: recipe.id,
          machineId: machine.id,
          amount,
          rateMode: "output",
          beaconCount: Math.min(target.beaconCount, machine.maxBeacons),
          constraints: first
            ? [
                {
                  id: `c-${target.id}`,
                  ingredientKey: `${first.type}:${first.name}`,
                  amount,
                },
              ]
            : [],
        };
      }),
    );
  };
  const activeTarget =
    targets.find((target) => target.id === activeTargetId) ?? targets.at(-1);
  const activeProductIcon = activeTarget
    ? PRODUCT_BY_KEY.get(activeTarget.productKey)?.icon
    : undefined;
  return (
    <div className="workspace-grid">
      <aside className="workspace-settings">
        <section className="panel-card">
          <SectionTitle
            number="+"
            title={tr(locale, "currentProducts")}
            icons={activeProductIcon ? [activeProductIcon] : []}
          />
          <ProductPicker locale={locale} onChange={(key) => add(key)} />
          <div className="mt-3 flex flex-wrap gap-2">
            {targets.map((target, index) => {
              const product = PRODUCT_BY_KEY.get(target.productKey)!;
              return (
                <button
                  type="button"
                  key={target.id}
                  className="product-chip flex items-center gap-1.5 rounded-md border bg-[#17191b] px-2 py-1 text-[10px]"
                  data-product-tone={index % 4}
                  data-active={target.id === activeTarget?.id}
                  onClick={() => promote(target.id)}
                  title={tr(locale, "moveProductToTop")}
                >
                  <FactorioIcon src={product.icon} alt="" size="sm" />
                  {localizedName(product.id, locale, product.type)}
                </button>
              );
            })}
          </div>
        </section>
        {targets.map((target, index) => (
          <ProductionTargetSettings
            key={target.id}
            target={target}
            qualityMode={qualityMode}
            locale={locale}
            onChange={(patch) => update(target.id, patch)}
            onActivate={() => setActiveTargetId(target.id)}
            onRemove={() => remove(target.id)}
            canRemove
            tone={index % 4}
          />
        ))}
      </aside>
      <section className="workspace-results">
        <section className="global-chain-master rounded-2xl border-2 border-[#f7a72d]/45 bg-[#111315] p-3 shadow-[0_20px_70px_rgba(247,167,45,.06)]">
          <ChainMasterPanel
            master={globalChainMaster}
            locale={locale}
            qualityMode={qualityMode}
            chains={activeChains}
            global
            onChange={applyGlobalChainMaster}
          />
          <p className="mt-2 rounded-lg border border-[#69c5df]/18 bg-[#69c5df]/7 px-3 py-2 text-[11px] leading-relaxed text-[#a8e8f7]">
            {tr(locale, "allChainsGenerated")}
          </p>
        </section>
        {!computed.length ? (
          <div className="panel-card flex min-h-56 flex-col items-center justify-center text-center">
            <Plus className="mb-3 size-8 text-[#f7a72d]" />
            <h2 className="text-lg font-semibold">
              {tr(locale, "noProductSelected")}
            </h2>
            <p className="mt-2 max-w-md text-xs text-zinc-500">
              {tr(locale, "selectProduct")}
            </p>
          </div>
        ) : null}
        {computed.map((entry, index) => (
          <ProductionTargetResult
            key={entry.target.id}
            computed={entry}
            qualityMode={qualityMode}
            locale={locale}
            onChange={(patch) => update(entry.target.id, patch)}
            onNavigate={(key, amount) => navigate(entry.target.id, key, amount)}
            energySelection={energySelections[entry.target.id]}
            onEnergyToggle={onEnergyToggle}
            tone={index % 4}
          />
        ))}
        <FactoryTotalsPanel
          snapshots={factorySnapshots}
          locale={locale}
        />
      </section>
    </div>
  );
}

const SECTION_META: Array<{
  id: CalculatorSection;
  icon: React.ReactNode;
  key:
    | "production"
    | "quality"
    | "science"
    | "energy"
    | "recycling"
    | "qualityRecycling"
    | "rocket"
    | "help";
}> = [
  { id: "science", icon: <FlaskConical />, key: "science" },
  { id: "production", icon: <Factory />, key: "production" },
  { id: "quality", icon: <Sparkles />, key: "quality" },
  { id: "recycling", icon: <Recycle />, key: "recycling" },
  { id: "quality-recycling", icon: <Recycle />, key: "qualityRecycling" },
  { id: "rocket", icon: <RocketIcon />, key: "rocket" },
  { id: "energy", icon: <Zap />, key: "energy" },
  { id: "help", icon: <CircleHelp />, key: "help" },
];

function selectedEnergyFlags(
  selections: Record<string, EnergySourceSelection>,
  mode: CalculatorSection,
) {
  return Object.values(selections)
    .filter(
      (source) =>
        source.mode === mode && (source.includeDirect || source.includeChain),
    )
    .map(
      (source) =>
        `${source.id}:${source.includeDirect ? 1 : 0}:${source.includeChain ? 1 : 0}`,
    )
    .sort()
    .join("|");
}

const MemoProductionModeWorkspace = memo(
  ProductionModeWorkspace,
  (previous, next) =>
    previous.locale === next.locale &&
    previous.qualityMode === next.qualityMode &&
    previous.onEnergySources === next.onEnergySources &&
    previous.onEnergyToggle === next.onEnergyToggle &&
    selectedEnergyFlags(
      previous.energySelections,
      previous.qualityMode ? "quality" : "production",
    ) ===
      selectedEnergyFlags(
        next.energySelections,
        next.qualityMode ? "quality" : "production",
      ),
);

const MemoScienceWorkspace = memo(
  ScienceWorkspace,
  (previous, next) =>
    previous.locale === next.locale &&
    previous.onEnergy === next.onEnergy &&
    previous.onEnergyToggle === next.onEnergyToggle &&
    previous.energySelection?.includeDirect ===
      next.energySelection?.includeDirect,
);

const MemoRocketFreightWorkspace = memo(
  RocketFreightWorkspace,
  (previous, next) =>
    previous.locale === next.locale &&
    previous.onEnergy === next.onEnergy &&
    previous.onEnergyToggle === next.onEnergyToggle &&
    previous.energySelection?.includeDirect ===
      next.energySelection?.includeDirect,
);

const MemoRecyclingWorkspace = memo(
  RecyclingWorkspace,
  (previous, next) =>
    previous.locale === next.locale &&
    previous.qualityMode === next.qualityMode &&
    previous.onEnergySources === next.onEnergySources &&
    previous.onEnergyToggle === next.onEnergyToggle &&
    selectedEnergyFlags(
      previous.energySelections,
      previous.qualityMode ? "quality-recycling" : "recycling",
    ) ===
      selectedEnergyFlags(
        next.energySelections,
        next.qualityMode ? "quality-recycling" : "recycling",
      ),
);

const MemoEnergyWorkspace = memo(EnergyWorkspace);

export function CalculatorApp({
  initialLocale = "en",
  publicLocaleRouting = false,
}: CalculatorAppProps = {}) {
  const [locale, setLocale] = useState<Locale>(initialLocale);
  const [section, setSection] = useState<CalculatorSection>("production");
  const [visitedSections, setVisitedSections] = useState<
    Set<CalculatorSection>
  >(() => new Set(["production"]));
  const [resetVersions, setResetVersions] = useState<
    Record<CalculatorSection, number>
  >({
    production: 0,
    quality: 0,
    science: 0,
    energy: 0,
    recycling: 0,
    "quality-recycling": 0,
    rocket: 0,
    help: 0,
  });
  const [energySources, setEnergySources] = useState<
    Record<string, EnergySourceSelection>
  >({});
  useEffect(() => {
    document.documentElement.lang = locale;
    if (publicLocaleRouting) updatePublicLocaleMetadata(locale);
  }, [locale, publicLocaleRouting]);
  const changeLocale = useCallback((nextLocale: Locale) => {
    setLocale(nextLocale);
  }, []);
  const replaceModeSources = useCallback(
    (mode: CalculatorSection, sources: EnergySourceSelection[]) => {
      setEnergySources((current) => {
        const next = Object.fromEntries(
          Object.entries(current).filter(([, value]) => value.mode !== mode),
        );
        sources.forEach((source) => {
          next[source.id] = {
            ...source,
            includeDirect:
              current[source.id]?.includeDirect ?? source.includeDirect,
            includeChain:
              current[source.id]?.includeChain ?? source.includeChain,
          };
        });
        const currentKeys = Object.keys(current);
        const nextKeys = Object.keys(next);
        if (
          currentKeys.length === nextKeys.length &&
          nextKeys.every((key) => sameEnergySource(current[key], next[key]))
        )
          return current;
        return next;
      });
    },
    [],
  );
  const updateScienceSource = useCallback((source: EnergySourceSelection) => {
    setEnergySources((current) => {
      const next = {
        ...source,
        includeDirect:
          current[source.id]?.includeDirect ?? source.includeDirect,
        includeChain:
          current[source.id]?.includeChain ?? source.includeChain,
      };
      return sameEnergySource(current[source.id], next)
        ? current
        : { ...current, [source.id]: next };
    });
  }, []);
  const toggleEnergy = useCallback(
    (id: string, field: "includeDirect" | "includeChain", value: boolean) => {
      setEnergySources((current) =>
        current[id] && current[id][field] !== value
          ? { ...current, [id]: { ...current[id], [field]: value } }
          : current,
      );
    },
    [],
  );
  const updateProductionSources = useCallback(
    (next: EnergySourceSelection[]) => replaceModeSources("production", next),
    [replaceModeSources],
  );
  const updateQualitySources = useCallback(
    (next: EnergySourceSelection[]) => replaceModeSources("quality", next),
    [replaceModeSources],
  );
  const updateRecyclingSources = useCallback(
    (next: EnergySourceSelection[]) => replaceModeSources("recycling", next),
    [replaceModeSources],
  );
  const updateQualityRecyclingSources = useCallback(
    (next: EnergySourceSelection[]) =>
      replaceModeSources("quality-recycling", next),
    [replaceModeSources],
  );
  const updateRocketSource = useCallback((source: EnergySourceSelection) => {
    setEnergySources((current) => {
      const next = {
        ...source,
        includeDirect:
          current[source.id]?.includeDirect ?? source.includeDirect,
        includeChain:
          current[source.id]?.includeChain ?? source.includeChain,
      };
      return sameEnergySource(current[source.id], next)
        ? current
        : { ...current, [source.id]: next };
    });
  }, []);
  const sources = useMemo(() => Object.values(energySources), [energySources]);
  const navigateToSection = useCallback((nextSection: CalculatorSection) => {
    setSection(nextSection);
    setVisitedSections((current) => {
      if (current.has(nextSection)) return current;
      const next = new Set(current);
      next.add(nextSection);
      return next;
    });
  }, []);
  return (
    <main className="app-shell">
      <header className="app-header">
        <div className="mx-auto flex max-w-[1900px] flex-col gap-4 px-4 py-4 sm:px-6">
          <div className="flex flex-col justify-between gap-3 sm:flex-row sm:items-center">
            <div className="flex items-center gap-3">
              <div className="flex size-10 items-center justify-center rounded-lg border border-[#f7a72d]/35 bg-[#f7a72d]/10">
                <Factory className="size-5 text-[#f7a72d]" />
              </div>
              <div>
                <h1 className="text-lg font-semibold">{tr(locale, "title")}</h1>
                <p className="font-mono text-[9px] uppercase tracking-wider text-zinc-600">
                  {tr(locale, "subtitle")}
                </p>
              </div>
            </div>
            <div className="flex flex-wrap items-center gap-2">
              <span className="badge-orange">
                Factorio {DATA_META.factorioVersion}
              </span>
              <span className="badge-muted">
                {DATA_META.visibleRecipes} {tr(locale, "recipeCount")}
              </span>
              <span className="badge-muted">
                {DATA_META.products} {tr(locale, "productCount")}
              </span>
              {section !== "help" ? (
                <Button
                  type="button"
                  variant="outline"
                  size="sm"
                  onClick={() => {
                    setResetVersions((current) => ({
                      ...current,
                      [section]: current[section] + 1,
                    }));
                    setEnergySources((current) =>
                      Object.fromEntries(
                        Object.entries(current).filter(
                          ([, source]) => source.mode !== section,
                        ),
                      ),
                    );
                  }}
                >
                  <RotateCcw className="size-3.5" />
                  {tr(locale, "resetCurrent")}
                </Button>
              ) : null}
              <Select
                value={locale}
                onValueChange={(v) => changeLocale(v as Locale)}
              >
                <SelectTrigger className="h-9 w-[180px] border-white/10 bg-[#17191b]">
                  <Languages className="size-4 text-[#69c5df]" />
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  {LOCALE_OPTIONS.map((option) => (
                    <SelectItem key={option.id} value={option.id}>
                      {languageLabel(option.id, locale)}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
          </div>
          <nav className="scrollbar-none flex gap-1 overflow-x-auto rounded-xl border border-white/8 bg-[#0c0e0f] p-1">
            {SECTION_META.map((entry) => (
              <button
                type="button"
                key={entry.id}
                onClick={() => navigateToSection(entry.id)}
                className={`flex shrink-0 items-center gap-2 rounded-lg px-3 py-2 text-xs transition ${section === entry.id ? "bg-[#303439] text-[#f7a72d]" : "text-zinc-500 hover:text-zinc-200"}`}
              >
                <span className="[&>svg]:size-4">{entry.icon}</span>
                {tr(locale, entry.key)}
              </button>
            ))}
          </nav>
        </div>
      </header>
      <div className="calculator-stage">
      {visitedSections.has("production") ? <div className={section === "production" ? "calculator-route" : "hidden"}>
        <MemoProductionModeWorkspace
          key={`p${resetVersions.production}`}
          locale={locale}
          qualityMode={false}
          onEnergySources={updateProductionSources}
          energySelections={energySources}
          onEnergyToggle={toggleEnergy}
        />
      </div> : null}
      {visitedSections.has("quality") ? <div className={section === "quality" ? "calculator-route" : "hidden"}>
        <MemoProductionModeWorkspace
          key={`q${resetVersions.quality}`}
          locale={locale}
          qualityMode
          onEnergySources={updateQualitySources}
          energySelections={energySources}
          onEnergyToggle={toggleEnergy}
        />
      </div> : null}
      {visitedSections.has("science") ? <div className={section === "science" ? "calculator-route" : "hidden"}>
        <MemoScienceWorkspace
          key={`s${resetVersions.science}`}
          locale={locale}
          onEnergy={updateScienceSource}
          energySelection={energySources.science}
          onEnergyToggle={toggleEnergy}
        />
      </div> : null}
      {visitedSections.has("energy") ? <div className={section === "energy" ? "calculator-route" : "hidden"}>
        <MemoEnergyWorkspace
          key={`e${resetVersions.energy}`}
          locale={locale}
          sources={sources}
          onToggle={toggleEnergy}
        />
      </div> : null}
      {visitedSections.has("recycling") ? <div className={section === "recycling" ? "calculator-route" : "hidden"}>
        <MemoRecyclingWorkspace
          key={`r${resetVersions.recycling}`}
          locale={locale}
          qualityMode={false}
          onEnergySources={updateRecyclingSources}
          energySelections={energySources}
          onEnergyToggle={toggleEnergy}
        />
      </div> : null}
      {visitedSections.has("quality-recycling") ? <div className={section === "quality-recycling" ? "calculator-route" : "hidden"}>
        <MemoRecyclingWorkspace
          key={`qr${resetVersions["quality-recycling"]}`}
          locale={locale}
          qualityMode
          onEnergySources={updateQualityRecyclingSources}
          energySelections={energySources}
          onEnergyToggle={toggleEnergy}
        />
      </div> : null}
      {visitedSections.has("rocket") ? <div className={section === "rocket" ? "calculator-route" : "hidden"}>
        <MemoRocketFreightWorkspace
          key={`rf${resetVersions.rocket}`}
          locale={locale}
          onEnergy={updateRocketSource}
          energySelection={energySources["rocket-freight"]}
          onEnergyToggle={toggleEnergy}
        />
      </div> : null}
      {visitedSections.has("help") ? <div className={section === "help" ? "calculator-route" : "hidden"}>
        <Suspense
          fallback={
            <div className="help-loading" aria-busy="true">
              <CircleHelp className="size-6" />
            </div>
          }
        >
          <HelpWorkspace locale={locale}
            onNavigate={navigateToSection}
          />
        </Suspense>
      </div> : null}
      </div>
      <ReleaseFooter
        locale={locale}
        showSourceDownload={publicLocaleRouting}
      />
    </main>
  );
}
