import { getUnitByCode } from "./registry";
import type { ConvertResult, SeedCountConvertResult, UnitDefinition } from "./types";

function toBaseValue(value: number, unit: UnitDefinition): number | null {
  if (unit.factorToBase == null) return null;
  const offset = unit.offsetToBase ?? 0;
  return value * unit.factorToBase + offset;
}

function fromBaseValue(baseValue: number, unit: UnitDefinition): number | null {
  if (unit.factorToBase == null || unit.factorToBase === 0) return null;
  const offset = unit.offsetToBase ?? 0;
  return (baseValue - offset) / unit.factorToBase;
}

export function convertUnitValue(
  value: number,
  fromCode: string,
  toCode: string
): ConvertResult {
  if (!Number.isFinite(value)) {
    return { ok: false, reason: "invalid_value" };
  }

  const fromUnit = getUnitByCode(fromCode);
  const toUnit = getUnitByCode(toCode);

  if (!fromUnit || !toUnit) {
    return { ok: false, reason: "missing_factor" };
  }

  if (!fromUnit.isConvertible || !toUnit.isConvertible) {
    return { ok: false, reason: "not_convertible" };
  }

  if (fromUnit.dimension !== toUnit.dimension) {
    return { ok: false, reason: "different_dimension" };
  }

  const baseValue = toBaseValue(value, fromUnit);
  if (baseValue == null) {
    return { ok: false, reason: "missing_factor" };
  }

  const targetValue = fromBaseValue(baseValue, toUnit);
  if (targetValue == null) {
    return { ok: false, reason: "missing_factor" };
  }

  return { ok: true, value: targetValue, baseValue };
}

export function convertToBase(value: number, fromCode: string): ConvertResult {
  const fromUnit = getUnitByCode(fromCode);
  if (!fromUnit || !Number.isFinite(value)) {
    return { ok: false, reason: "invalid_value" };
  }
  if (!fromUnit.isConvertible) {
    return { ok: false, reason: "not_convertible" };
  }
  const baseValue = toBaseValue(value, fromUnit);
  if (baseValue == null) {
    return { ok: false, reason: "missing_factor" };
  }
  return { ok: true, value: baseValue, baseValue };
}

/** 粒数 → 重量(g)，需千粒重 TKW (g/1000粒) */
export function seedCountToWeightGram(count: number, thousandKernelWeightG: number): SeedCountConvertResult {
  if (!Number.isFinite(count) || !Number.isFinite(thousandKernelWeightG)) {
    return { ok: false, reason: "invalid_value" };
  }
  if (thousandKernelWeightG <= 0) {
    return { ok: false, reason: "invalid_tkw" };
  }
  return { ok: true, value: (count * thousandKernelWeightG) / 1000 };
}

/** 重量(g) → 粒数，需千粒重 TKW (g/1000粒) */
export function weightGramToSeedCount(weightG: number, thousandKernelWeightG: number): SeedCountConvertResult {
  if (!Number.isFinite(weightG) || !Number.isFinite(thousandKernelWeightG)) {
    return { ok: false, reason: "invalid_value" };
  }
  if (thousandKernelWeightG <= 0) {
    return { ok: false, reason: "invalid_tkw" };
  }
  return { ok: true, value: (weightG * 1000) / thousandKernelWeightG };
}

/** 包装单位换算：数量 × 规格 = 基准量 */
export function packageToBaseAmount(
  packageCount: number,
  specAmount: number,
  specUnitCode: string
): ConvertResult {
  if (!Number.isFinite(packageCount) || !Number.isFinite(specAmount)) {
    return { ok: false, reason: "invalid_value" };
  }
  const total = packageCount * specAmount;
  return convertToBase(total, specUnitCode);
}

export function formatUnitNumber(value: number, maxFractionDigits = 6): string {
  if (!Number.isFinite(value)) return "—";
  const abs = Math.abs(value);
  if (abs === 0) return "0";
  if (abs >= 1_000_000 || (abs > 0 && abs < 0.0001)) {
    return value.toExponential(4);
  }
  return value.toLocaleString("zh-CN", {
    maximumFractionDigits: maxFractionDigits,
    minimumFractionDigits: 0,
  });
}

export const CONVERT_ERROR_MESSAGES = {
  missing_factor: "缺少换算系数",
  different_dimension: "维度不同，无法直接换算",
  not_convertible: "该单位不可直接换算（包装单位需规格，粒数需千粒重）",
  invalid_value: "请输入有效数值",
  missing_tkw: "请填写千粒重 (g/1000粒)",
  invalid_tkw: "千粒重必须大于 0",
} as const;
