export type ItemKind = "item" | "fluid";
export type EffectKind =
  "consumption" | "speed" | "productivity" | "pollution" | "quality";
export type ModuleFamily = "productivity" | "speed" | "quality" | "efficiency";
export type QualityId = "normal" | "uncommon" | "rare" | "epic" | "legendary";
export type RateUnit = "s" | "min" | "h";
export type Locale =
  "en" | "de" | "es-ES" | "fr" | "it" | "ja" | "ru" | "zh-CN" | "zh-TW";
export type CalculatorSection =
  | "production"
  | "quality"
  | "science"
  | "energy"
  | "recycling"
  | "quality-recycling"
  | "rocket"
  | "help";
export type ItemGroupId =
  | "logistics"
  | "production"
  | "intermediate-products"
  | "space"
  | "combat"
  | "fluids";

export interface Quality {
  id: QualityId;
  name: string;
  level: number;
  multiplier: number;
  beaconPowerMultiplier: number;
  color: string;
  icon: string;
}

export interface RecipeIngredient {
  name: string;
  type: ItemKind;
  amount: number;
  ignoredByStats: number;
  fluidboxIndex?: number;
}

export interface RecipeProduct {
  name: string;
  type: ItemKind;
  amount: number;
  probability: number;
  ignoredByProductivity: number;
  ignoredByStats: number;
  fluidboxIndex?: number;
}

export interface Recipe {
  id: string;
  name: string;
  categories: string[];
  energy: number;
  ingredients: RecipeIngredient[];
  products: RecipeProduct[];
  allowProductivity: boolean;
  allowQuality: boolean;
  subgroup?: string;
  order?: string;
  icon: string;
  passive?: boolean;
  surfaceConditions?: Array<{ property: string; min?: number; max?: number }>;
}

export interface ProductOption {
  key: string;
  id: string;
  type: ItemKind;
  name: string;
  icon: string;
  recipeIds: string[];
  group: ItemGroupId;
  subgroup?: string;
  order?: string;
}

export interface Machine {
  id: string;
  shortName: string;
  name: string;
  icon: string;
  categories: string[];
  speed: number;
  moduleSlots: number;
  allowedEffects: EffectKind[];
  baseProductivity: number;
  energyKw: number;
  energyKind: "electric" | "burner" | "nutrients" | "food" | "passive";
  fuelItem?: string;
  fuelValueKj?: number;
  drainKw?: number;
  width: number;
  height: number;
  maxBeacons: number;
  heatingKw?: number;
  auxiliaryActiveKw?: number;
}

export interface ModuleDefinition {
  family: ModuleFamily;
  tier: 1 | 2 | 3;
  name: string;
  icon: string;
  effects: Partial<Record<EffectKind, number>>;
}

export interface ModuleSelection {
  family: ModuleFamily;
  tier: 1 | 2 | 3;
  quality: QualityId;
}

export interface EffectTotals {
  consumption: number;
  speed: number;
  productivity: number;
  pollution: number;
  quality: number;
}

export interface QualityAmount {
  quality: QualityId | null;
  amount: number;
}

export interface MaterialFlow {
  id: string;
  name: string;
  type: ItemKind;
  icon: string;
  amounts: QualityAmount[];
  total: number;
  gross?: number;
  returned?: number;
}

export interface InputConstraint {
  id: string;
  ingredientKey: string;
  amount: number;
}

export interface CalculatorInput {
  recipe: Recipe;
  product: ProductOption;
  machine: Machine;
  machineQuality: QualityId;
  inputQuality: QualityId;
  /**
   * Expected share of recipe cycles run with each ingredient quality.
   *
   * Factorio crafts one quality tier per cycle.  The full-chain quality
   * solver uses this distribution to combine those separate batches while
   * the regular calculator continues to use `inputQuality` on its own.
   */
  inputQualityDistribution?: QualityAmount[];
  outputQuality: QualityId | "total";
  maxQuality?: QualityId;
  calculationMode?: "normal" | "quality";
  machineModules: Array<ModuleSelection | null>;
  beaconModules: Array<ModuleSelection | null>;
  beaconQuality: QualityId;
  beaconCount: number;
  isolatedBeacons?: boolean;
  mode: "output" | "input";
  amount: number;
  unit: RateUnit;
  inputConstraints: InputConstraint[];
}

export interface TilePlacement {
  kind: "machine" | "beacon" | "entity" | "link";
  x: number;
  y: number;
  width: number;
  height: number;
  machineIndex?: number;
  affects?: number[];
  entityId?: string;
  productId?: string;
  productType?: ItemKind;
  flowDirection?: "input" | "output";
  labelAnchor?: { x: number; y: number };
  label?: string;
  tone?: "machine" | "power" | "heat" | "fluid" | "storage";
  direction?: "north" | "east" | "south" | "west";
  beltEnd?: "input" | "output";
  mirror?: boolean;
}

export interface BeaconLayoutResult {
  requestedPerMachine: number;
  machineCount: number;
  counts: number[];
  average: number;
  min: number;
  max: number;
  uniqueBeacons: number;
  exact: boolean;
  extrapolated: boolean;
  corridor: number;
  placements: TilePlacement[];
  bounds: { minX: number; maxX: number; minY: number; maxY: number };
}

export interface CalculationResult {
  valid: boolean;
  message?: string;
  cyclesPerSecond: number;
  ratePerSecond: number;
  inputs: MaterialFlow[];
  outputs: MaterialFlow[];
  targetPerCycle: number;
  limitingInput?: string;
  machineEffects: EffectTotals;
  isolatedBeaconEffects: EffectTotals;
  craftingSpeed: number;
  productivityBonus: number;
  qualityChance: number;
  theoreticalMachines: number;
  machinesToBuild: number;
  utilization: number;
  idealIsolatedMachines: number;
  beaconLayout: BeaconLayoutResult;
  electricTargetKw: number;
  electricFullLoadKw: number;
  machineElectricTargetKw: number;
  beaconElectricKw: number;
  fuelTargetKw: number;
  nutrientItemsPerSecond: number;
  idleDrainKw: number;
  heatingKw: number;
  qualityDistribution: QualityAmount[];
  warnings: string[];
}

export type InserterHandoff =
  "belt-machine" | "container-machine" | "machine-belt" | "machine-container";
export interface LogisticsSettings {
  inserterId: "inserter" | "fast-inserter" | "bulk-inserter" | "stack-inserter";
  inserterQuality: QualityId;
  capacityBonus: number;
  handoff: InserterHandoff;
}
export interface LogisticsFlow {
  id: string;
  name: string;
  icon: string;
  type: ItemKind;
  direction: "input" | "output";
  totalPerSecond: number;
  perMachineMin: number;
  perMachineMax: number;
  insertersPerMachine?: number;
  totalInserters?: number;
  pumps?: number;
  beltLanes?: number;
  warning?: string;
}
export interface LogisticsResult {
  flows: LogisticsFlow[];
  electricKw: number;
  warnings: string[];
}

export interface ChainOverride {
  recipeId?: string;
  machineId?: string;
  machineQuality?: QualityId;
  machineModuleFamily?: ModuleFamily | "none";
  machineModuleFamilies?: ModuleFamily[];
  machineModuleTier?: 1 | 2 | 3;
  machineModuleQuality?: QualityId;
  beaconEnabled?: boolean;
  beaconMode?: "standard" | "quality-safe";
  beaconCount?: number;
  beaconModuleFamily?: "speed" | "efficiency" | "none";
  beaconModuleTier?: 1 | 2 | 3;
  beaconModuleQuality?: QualityId;
  beaconQuality?: QualityId;
  inserterId?: LogisticsSettings["inserterId"];
  inserterQuality?: QualityId;
  inserterCapacityBonus?: number;
  inserterHandoff?: InserterHandoff;
  includeEnergy?: boolean;
}

export type MiningDrillId =
  | "burner-mining-drill"
  | "electric-mining-drill"
  | "big-mining-drill";

export interface ChainMasterSettings {
  preferredMachineId: string | "auto";
  /** Mining drill used for mineable raw-resource source sizing. */
  miningDrillId?: MiningDrillId;
  /** One module family used to fill every available mining-drill slot. */
  miningModuleFamily?: ModuleFamily | "none";
  miningModuleTier?: 1 | 2 | 3;
  miningModuleQuality?: QualityId;
  /** Machines the player has unlocked and permits the automatic chain solver to use. */
  unlockedMachineIds: string[];
  /** Ordered machine preference within broad recipe families. */
  machinePriorities: Record<string, string[]>;
  processMachineChoices?: Record<
    string,
    { recipeId: string; machineId: string }
  >;
  machineQuality: QualityId;
  machineModuleFamilies: ModuleFamily[];
  machineModuleTier: 1 | 2 | 3;
  machineModuleQuality: QualityId;
  beaconEnabled: boolean;
  beaconMode: "standard" | "quality-safe";
  beaconCount: number;
  beaconModuleFamily: "speed" | "efficiency" | "none";
  beaconModuleTier: 1 | 2 | 3;
  beaconModuleQuality: QualityId;
  beaconQuality: QualityId;
  inserterId: LogisticsSettings["inserterId"];
  inserterQuality: QualityId;
  inserterCapacityBonus: number;
  inserterHandoff: InserterHandoff;
}

export interface ChainSource {
  kind: "source";
  key: string;
  id: string;
  name: string;
  icon: string;
  type: ItemKind;
  ratePerSecond: number;
  requiredQuality?: QualityId;
  requiredAmounts?: QualityAmount[];
  /** Gross source output, including quality grades not consumed by this chain. */
  outputAmounts?: QualityAmount[];
  entities: number;
  entityId?: string;
  entityName: string;
  moduleSlots?: number;
  modules?: Array<ModuleSelection | null>;
  qualityChance?: number;
  electricKw: number;
  includeEnergy: boolean;
  depth: number;
}

export interface ProductionChainNode {
  kind: "recipe";
  key: string;
  productKey: string;
  product: ProductOption;
  ratePerSecond: number;
  requiredQuality?: QualityId;
  requiredAmounts?: QualityAmount[];
  calculatorInput: CalculatorInput;
  recipe: Recipe;
  machine: Machine;
  result: CalculationResult;
  logistics: LogisticsResult;
  logisticsSettings: LogisticsSettings;
  electricKw: number;
  includeEnergy: boolean;
  depth: number;
  inputs: Array<ProductionChainNode | ChainSource>;
  cycle?: boolean;
}

export interface ProductionChainResult {
  root: ProductionChainNode;
  rootInput: CalculatorInput;
  rootResult: CalculationResult;
  qualityCoupled: boolean;
  totalElectricKw: number;
  includedElectricKw: number;
  rawSources: ChainSource[];
  warnings: string[];
}

export interface ScienceInput {
  labId: "lab" | "biolab";
  labQuality: QualityId;
  packQuality: QualityId;
  mode: "actual" | "effective";
  amountPerMinute: number;
  machineModules: Array<ModuleSelection | null>;
  beaconEnabled: boolean;
  beaconCount: number;
  biolabBeaconMode: "optimized" | "manual";
  beaconModules: Array<ModuleSelection | null>;
  beaconQuality: QualityId;
}
export interface ScienceResult {
  actualSpm: number;
  effectiveSpm: number;
  effectivePerPack: number;
  actualCapacityPerLab: number;
  effectiveCapacityPerLab: number;
  labsTheoretical: number;
  labsToBuild: number;
  researchSpeed: number;
  packDrainMultiplier: number;
  electricKw: number;
  beaconLayout: BeaconLayoutResult;
  forcedBiolabRing: boolean;
}

export type EnergyTechnology =
  "steam" | "solar" | "nuclear" | "heating-tower" | "fusion";
export interface EnergySourceSelection {
  id: string;
  label: string;
  icon: string;
  directKw: number;
  chainKw: number;
  includeDirect: boolean;
  includeChain: boolean;
  mode: CalculatorSection;
}
export interface EnergyInput {
  targetMw: number;
  technology: EnergyTechnology;
  quality: QualityId;
  reservePercent: number;
  planet: "nauvis" | "vulcanus" | "gleba" | "fulgora" | "aquilo" | "space";
  nuclearWidth: number;
  nuclearHeight: number;
  fusionMode: "demand" | "fixed";
  fusionReactors: 1 | 2 | 3 | 4;
  steamGenerator?: "steam-engine" | "steam-turbine";
}
export interface EnergyResult {
  netMw: number;
  grossMw: number;
  entities: Array<{
    id: string;
    name: string;
    icon: string;
    amount: number;
    detail?: string;
  }>;
  inputs: Array<{ id: string; name: string; icon: string; perSecond: number }>;
  notes: string[];
  blueprint?: BeaconLayoutResult;
  fusion?: {
    reactorsPerBlock: number;
    blocks: number;
    reactors: number;
    generators: number;
    grossMw: number;
    internalMw: number;
    netMw: number;
    cellsPerSecond: number;
  };
}

export interface RocketFreightInput {
  productId: string;
  source: string;
  destination: string;
  targetRate: number;
  unit: RateUnit;
  cargoPerTransit: number;
  siloQuality: QualityId;
  rocketPartProductivityLevel: number;
  siloModules: Array<ModuleSelection | null>;
  beaconCount: number;
  beaconModules: Array<ModuleSelection | null>;
  beaconQuality: QualityId;
  speedMode: "manual" | "thrusters";
  manualSpeedKms: number;
  thrusterCount: number;
  thrusterQuality: QualityId;
  thrusterFill: number;
  platformMassTons: number;
  platformWidthTiles: number;
  cargoBays: number;
  cargoBayQuality?: QualityId;
  loadingMode?: "robots" | "inserters" | "ignore";
  loadingInserterId?: "inserter" | "fast-inserter" | "bulk-inserter" | "stack-inserter";
  loadingInserterQuality?: QualityId;
  loadingInserterCapacityBonus?: number;
  logisticRobotCount?: number;
  workerRobotSpeedLevel?: number;
  workerRobotCargoLevel?: number;
  includeEnergy: boolean;
}

export interface RocketFreightResult {
  valid: boolean;
  message?: string;
  distanceKm: number;
  path: string[];
  speedKms: number;
  flightSeconds: number;
  roundTripSeconds: number;
  cargoCapacityPerRocket: number;
  launchesPerTransit: number;
  launchesPerMinute: number;
  siloCycleSeconds: number;
  rocketPartCraftSeconds: number;
  sustainedSilos: number;
  waveSilos: number;
  silosToPlace: number;
  speedLimitedSilos: number;
  payloadWaveSilos: number;
  siloBottleneck: "throughput" | "payload-wave";
  loadingSeconds: number;
  payloadInsertionSeconds: number;
  payloadInsertionRate: number;
  inserterInsertionSeconds: number;
  robotFlightSeconds: number;
  robotSupplySeconds: number;
  robotSupplyRate: number;
  robotCargoCapacity: number;
  logisticRobotCount: number;
  landingSeconds: number;
  landingWaves: number;
  platformsRequired: number;
  requestedCargoPerTransit: number;
  effectiveCargoPerTransit: number;
  platformCargoCapacity: number;
  cargoBaySlotsEach: number;
  minimumCargoBays: number;
  cargoStorageLimited: boolean;
  rocketPartIngredientsPerSecond: Array<{
    id: string;
    amount: number;
    icon: string;
  }>;
  thrusterFuelPerSecond: number;
  thrusterOxidizerPerSecond: number;
  electricKw: number;
  siloLayout: BeaconLayoutResult;
  notes: string[];
}

export interface RecyclingRoute {
  id: string;
  productId: string;
  productName: string;
  productIcon: string;
  sourceRecipeId?: string;
  sourceRecipeName?: string;
  energy: number;
  outputs: Array<{
    id: string;
    type: ItemKind;
    amount: number;
    icon: string;
    name: string;
  }>;
  lostFluids: Array<{ id: string; amount: number; icon: string; name: string }>;
  qualityEligible: boolean;
}
export interface RecyclingInput {
  route: RecyclingRoute;
  amount: number;
  unit: RateUnit;
  inputQuality: QualityId;
  maxQuality: QualityId;
  recyclerQuality: QualityId;
  modules: Array<ModuleSelection | null>;
  beaconEnabled: boolean;
  beaconCount?: number;
  beaconModules: Array<ModuleSelection | null>;
  beaconQuality: QualityId;
  qualityMode: boolean;
  targetOutputId?: string;
  targetQuality?: QualityId | "total";
  amountMode?: "input" | "target-output";
}
export interface RecyclingResult {
  inputPerSecond: number;
  targetOutputPerSecond: number;
  recyclerTimeSeconds: number;
  throughputPerRecycler: number;
  theoreticalRecyclers: number;
  recyclersToBuild: number;
  utilization: number;
  craftingSpeed: number;
  qualityChance: number;
  electricKw: number;
  outputs: MaterialFlow[];
  lostFluids: MaterialFlow[];
  beaconLayout: BeaconLayoutResult;
  warnings: string[];
}
