export type UnitKind =
  | "length"
  | "angle"
  | "time"
  | "mass"
  | "linear_velocity"
  | "angular_velocity"
  | "linear_acceleration"
  | "angular_acceleration"
  | "percent";

export interface UnitDefinition {
  literal: string;
  kind: UnitKind;
  siUnit: string;
  factor: number;
}

const UNIT_DEFINITIONS: UnitDefinition[] = [
  { literal: "m", kind: "length", siUnit: "m", factor: 1 },
  { literal: "mm", kind: "length", siUnit: "m", factor: 0.001 },
  { literal: "rad", kind: "angle", siUnit: "rad", factor: 1 },
  { literal: "deg", kind: "angle", siUnit: "rad", factor: Math.PI / 180 },
  { literal: "s", kind: "time", siUnit: "s", factor: 1 },
  { literal: "ms", kind: "time", siUnit: "s", factor: 0.001 },
  { literal: "kg", kind: "mass", siUnit: "kg", factor: 1 },
  { literal: "m/s", kind: "linear_velocity", siUnit: "m/s", factor: 1 },
  { literal: "mm/s", kind: "linear_velocity", siUnit: "m/s", factor: 0.001 },
  { literal: "rad/s", kind: "angular_velocity", siUnit: "rad/s", factor: 1 },
  { literal: "deg/s", kind: "angular_velocity", siUnit: "rad/s", factor: Math.PI / 180 },
  { literal: "m/s2", kind: "linear_acceleration", siUnit: "m/s2", factor: 1 },
  { literal: "m/s^2", kind: "linear_acceleration", siUnit: "m/s2", factor: 1 },
  { literal: "mm/s2", kind: "linear_acceleration", siUnit: "m/s2", factor: 0.001 },
  { literal: "mm/s^2", kind: "linear_acceleration", siUnit: "m/s2", factor: 0.001 },
  { literal: "rad/s2", kind: "angular_acceleration", siUnit: "rad/s2", factor: 1 },
  { literal: "rad/s^2", kind: "angular_acceleration", siUnit: "rad/s2", factor: 1 },
  { literal: "deg/s2", kind: "angular_acceleration", siUnit: "rad/s2", factor: Math.PI / 180 },
  { literal: "deg/s^2", kind: "angular_acceleration", siUnit: "rad/s2", factor: Math.PI / 180 },
  { literal: "%", kind: "percent", siUnit: "ratio", factor: 0.01 }
];

const UNITS = new Map(UNIT_DEFINITIONS.map((definition) => [definition.literal, definition]));

export function normalizeUnitLiteral(literal: string): UnitDefinition {
  const definition = UNITS.get(literal);
  if (!definition) {
    throw new Error(`Unknown GRL unit: ${literal}`);
  }
  return definition;
}

export function isGrlUnitLiteral(literal: string): boolean {
  return UNITS.has(literal);
}

export function normalizeUnitValue(value: number, unitLiteral: string): number {
  const unit = normalizeUnitLiteral(unitLiteral);
  return value * unit.factor;
}
