import { isBoolean, isObject, isValidFiniteNumber, makeFixer } from './utils';

export type WarpMarkers = Readonly<Record<number, number>>;

export type Warp = {
  awaitingAnalysis: boolean;
  speed: number;
  enabled: boolean;
  markers: WarpMarkers;
};

export const WARP_SPEED_MINIMUM = 1 / 128;
export const WARP_SPEED_MAXIMUM = 128;

export const fixWarpAwaitingAnalysis = makeFixer(isBoolean, false);

export const fixWarpEnabled = makeFixer(isBoolean, true);

export const fixWarpSpeed = (speed: unknown): number => {
  if (!isValidFiniteNumber(speed)) {
    return 1.0;
  }
  return Math.max(WARP_SPEED_MINIMUM, Math.min(WARP_SPEED_MAXIMUM, speed));
};

export const fixWarpMarkers = (markers: unknown): WarpMarkers => {
  if (!isObject(markers)) {
    return {};
  }
  // Validate and remove invalid keys in place to maintain referential stability
  for (const [key, value] of Object.entries(markers)) {
    const numKey = Number(key);
    if (!isValidFiniteNumber(numKey) || !isValidFiniteNumber(value)) {
      delete markers[key];
    }
  }
  return markers as WarpMarkers;
};

export default function fixWarp(warp: unknown): Warp {
  if (!isObject(warp)) {
    return {
      awaitingAnalysis: fixWarpAwaitingAnalysis(undefined),
      speed: fixWarpSpeed(undefined),
      enabled: fixWarpEnabled(undefined),
      markers: fixWarpMarkers(undefined),
    };
  }

  const w = warp as {
    awaitingAnalysis: unknown;
    speed: unknown;
    enabled: unknown;
    markers: unknown;
  };

  w.awaitingAnalysis = fixWarpAwaitingAnalysis(w.awaitingAnalysis);
  w.speed = fixWarpSpeed(w.speed);
  w.enabled = fixWarpEnabled(w.enabled);
  w.markers = fixWarpMarkers(w.markers);

  return warp as Warp;
}
