import * as VScript from "http://172.16.0.12/bladerunner_sdk/vscript@2.5.2/deno/release/mod.ts";
import * as VAPI from "./mod.ts";
export const lift = {
  Action: (
    _raw: [0, [boolean, number]] | [1, [number]] | [2, []],
    _socket: VScript.VSocket,
  ): Action => {
    switch (_raw[0]) {
      case 0:
        return {
          variant: "Jump",
          value: VAPI.Servos.lift.ActionJump(_raw[1], _socket),
        };
      case 1:
        return {
          variant: "Slew",
          value: VAPI.Servos.lift.ActionSlew(_raw[1], _socket),
        };
      case 2:
        return {
          variant: "Reset",
          value: VAPI.Servos.lift.ActionReset(_raw[1], _socket),
        };
    }
  },
  CounterThresholds: (
    _raw: [number, number],
    _socket: VScript.VSocket,
  ): CounterThresholds => {
    return {
      promotion: _raw[0],
      demotion: _raw[1],
    };
  },
  Counters: (
    _raw: [number, number, number, number, number, number, number],
    _socket: VScript.VSocket,
  ): Counters => {
    return {
      missing_offset: _raw[0],
      missing_drift: _raw[1],
      bp_overall: _raw[2],
      bp_offset: _raw[3],
      bp_offset_errors: _raw[4],
      bp_drift: _raw[5],
      bp_drift_errors: _raw[6],
    };
  },
  CurrentEstimate: (
    _raw: [
      [number, number, number, number],
      null | [number, number, number, number],
    ],
    _socket: VScript.VSocket,
  ): CurrentEstimate => {
    return {
      offset: VAPI.Time.lift.TimestampedOffset(_raw[0], _socket),
      drift:
        _raw[1] === null
          ? null
          : VAPI.Time.lift.TimestampedDrift(_raw[1], _socket),
    };
  },
  DriftThresholds: (
    _raw: [number, number],
    _socket: VScript.VSocket,
  ): DriftThresholds => {
    return {
      holdover: _raw[0],
      convergence: _raw[1],
    };
  },
  ModeFreeRun: (_raw: [boolean], _socket: VScript.VSocket): ModeFreeRun => {
    return { reset_drift: _raw[0] };
  },
  ActionJump: (
    _raw: [boolean, number],
    _socket: VScript.VSocket,
  ): ActionJump => {
    return {
      rough: _raw[0],
      delta_t: VScript.VAPIHelpers.liftSeconds(_raw[1], _socket),
    };
  },
  ModeLockToInput: (_raw: [], _socket: VScript.VSocket): ModeLockToInput => {
    return {};
  },
  ModeManual: (
    _raw: [number, number],
    _socket: VScript.VSocket,
  ): ModeManual => {
    return {
      relative_speed: _raw[0],
      offset: VScript.VAPIHelpers.liftSeconds(_raw[1], _socket),
    };
  },
  Metrics: (
    _raw: [
      VAPI.Servos.State,
      null | number,
      number,
      number,
      (
        | null
        | [
            [number, number, number, number],
            null | [number, number, number, number],
          ]
      ),
      [number, number, number, number, number, number, number],
      number,
    ],
    _socket: VScript.VSocket,
  ): Metrics => {
    return {
      state: _raw[0],
      continuity_index: _raw[1],
      speed: _raw[2],
      max_rel_acceleration: _raw[3],
      current_estimate:
        _raw[4] === null
          ? null
          : VAPI.Servos.lift.CurrentEstimate(_raw[4], _socket),
      counters: VAPI.Servos.lift.Counters(_raw[5], _socket),
      attempting_calibration_for: VScript.VAPIHelpers.liftNanoseconds(
        _raw[6],
        _socket,
      ),
    };
  },
  Mode: (
    _raw: [0, []] | [1, [boolean]] | [2, [number, number]],
    _socket: VScript.VSocket,
  ): Mode => {
    switch (_raw[0]) {
      case 0:
        return {
          variant: "LockToInput",
          value: VAPI.Servos.lift.ModeLockToInput(_raw[1], _socket),
        };
      case 1:
        return {
          variant: "FreeRun",
          value: VAPI.Servos.lift.ModeFreeRun(_raw[1], _socket),
        };
      case 2:
        return {
          variant: "Manual",
          value: VAPI.Servos.lift.ModeManual(_raw[1], _socket),
        };
    }
  },
  OffsetThresholds: (
    _raw: [number, number, number, number],
    _socket: VScript.VSocket,
  ): OffsetThresholds => {
    return {
      rough_jump: VScript.VAPIHelpers.liftSeconds(_raw[0], _socket),
      holdover: VScript.VAPIHelpers.liftSeconds(_raw[1], _socket),
      convergence: VScript.VAPIHelpers.liftSeconds(_raw[2], _socket),
      inner_target_corridor: VScript.VAPIHelpers.liftSeconds(_raw[3], _socket),
    };
  },
  PLLParameters: (
    _raw: [number, number, number, number, number],
    _socket: VScript.VSocket,
  ): PLLParameters => {
    return {
      min_drift_adjustment_step: _raw[0],
      max_drift_adjustment_step: _raw[1],
      drift_growth_factor: _raw[2],
      stiffness: _raw[3],
      damping: _raw[4],
    };
  },
  ParameterRegime: (
    _raw: [
      [number, number, number, number, number],
      [number, number],
      [number, number, number, number],
      [number, number],
    ],
    _socket: VScript.VSocket,
  ): ParameterRegime => {
    return {
      pll: VAPI.Servos.lift.PLLParameters(_raw[0], _socket),
      speed_limits: VAPI.Servos.lift.ParameterRegimeSpeedLimits(
        _raw[1],
        _socket,
      ),
      offset_thresholds: VAPI.Servos.lift.OffsetThresholds(_raw[2], _socket),
      drift_thresholds: VAPI.Servos.lift.DriftThresholds(_raw[3], _socket),
    };
  },
  ActionReset: (_raw: [], _socket: VScript.VSocket): ActionReset => {
    return {};
  },
  Settings: (
    _raw: [
      [
        [number, number, number, number, number],
        [number, number],
        [number, number, number, number],
        [number, number],
      ],
      [
        [number, number, number, number, number],
        [number, number],
        [number, number, number, number],
        [number, number],
      ],
      VAPI.Servos.LockingPolicy,
      [number, number],
      number,
      VAPI.Servos.OnCalibrationTimeout,
    ],
    _socket: VScript.VSocket,
  ): Settings => {
    return {
      uncalibrated: VAPI.Servos.lift.ParameterRegime(_raw[0], _socket),
      calibrated: VAPI.Servos.lift.ParameterRegime(_raw[1], _socket),
      locking_policy: _raw[2],
      counter_thresholds: VAPI.Servos.lift.CounterThresholds(_raw[3], _socket),
      calibration_timeout: VScript.VAPIHelpers.liftNanoseconds(
        _raw[4],
        _socket,
      ),
      on_calibration_timeout: _raw[5],
    };
  },
  ActionSlew: (_raw: [number], _socket: VScript.VSocket): ActionSlew => {
    return { target_speed: _raw[0] };
  },
  ParameterRegimeSpeedLimits: (
    _raw: [number, number],
    _socket: VScript.VSocket,
  ): ParameterRegimeSpeedLimits => {
    return {
      min: _raw[0],
      max: _raw[1],
    };
  },
} as const;
export const lower = {
  Action: (
    _x:
      | { variant: "Jump"; value: VAPI.Servos.ActionJump }
      | { variant: "Slew"; value: VAPI.Servos.ActionSlew }
      | { variant: "Reset"; value: VAPI.Servos.ActionReset },
    _socket: VScript.VSocket,
  ): [0, [boolean, number]] | [1, [number]] | [2, []] => {
    switch (_x.variant) {
      case "Jump":
        return [0, VAPI.Servos.lower.ActionJump(_x.value, _socket)];
      case "Slew":
        return [1, VAPI.Servos.lower.ActionSlew(_x.value, _socket)];
      case "Reset":
        return [2, VAPI.Servos.lower.ActionReset(_x.value, _socket)];
    }
  },
  CounterThresholds: (
    _x: { promotion: number; demotion: number },
    _socket: VScript.VSocket,
  ): [number, number] => [_x.promotion, _x.demotion],
  Counters: (
    _x: {
      missing_offset: VAPI.Primitives.SaturatingCounter16;
      missing_drift: VAPI.Primitives.SaturatingCounter16;
      bp_overall: VAPI.Primitives.SaturatingSignedCounter16;
      bp_offset: VAPI.Primitives.SaturatingSignedCounter16;
      bp_offset_errors: VAPI.Primitives.SaturatingSignedCounter16;
      bp_drift: VAPI.Primitives.SaturatingSignedCounter16;
      bp_drift_errors: VAPI.Primitives.SaturatingSignedCounter16;
    },
    _socket: VScript.VSocket,
  ): [number, number, number, number, number, number, number] => [
    _x.missing_offset,
    _x.missing_drift,
    _x.bp_overall,
    _x.bp_offset,
    _x.bp_offset_errors,
    _x.bp_drift,
    _x.bp_drift_errors,
  ],
  CurrentEstimate: (
    _x: {
      offset: VAPI.Time.TimestampedOffset;
      drift: null | VAPI.Time.TimestampedDrift;
    },
    _socket: VScript.VSocket,
  ): [
    [number, number, number, number],
    null | [number, number, number, number],
  ] => [
    VAPI.Time.lower.TimestampedOffset(_x.offset, _socket),
    _x.drift === null
      ? null
      : VAPI.Time.lower.TimestampedDrift(_x.drift, _socket),
  ],
  DriftThresholds: (
    _x: { holdover: number; convergence: number },
    _socket: VScript.VSocket,
  ): [number, number] => [_x.holdover, _x.convergence],
  ModeFreeRun: (
    _x: { reset_drift: boolean },
    _socket: VScript.VSocket,
  ): [boolean] => [_x.reset_drift],
  ActionJump: (
    _x: { rough: boolean; delta_t: VScript.Duration },
    _socket: VScript.VSocket,
  ): [boolean, number] => [
    _x.rough,
    VScript.VAPIHelpers.lowerSeconds(_x.delta_t, _socket),
  ],
  ModeLockToInput: (_x: {}, _socket: VScript.VSocket): [] => [],
  ModeManual: (
    _x: { relative_speed: number; offset: VScript.Duration },
    _socket: VScript.VSocket,
  ): [number, number] => [
    _x.relative_speed,
    VScript.VAPIHelpers.lowerSeconds(_x.offset, _socket),
  ],
  Metrics: (
    _x: {
      state: VAPI.Servos.State;

      /**
      Most clock control units continuously adjust their target's operating
      frequency until the time and/or frequency offset between source and
      target matches a user-defined value. These units require no data beyond
      frame rate, source type, frequency offset and offset.
      
      However, other clock operations implicitly guarantee synchronicity by
      rigidly linking their target's operating frequency to the source
      frequency. This implicit link may be broken when the timing source
      changes discontinuously. For example, an uncalibrated PTP clock may
      perform arbitrarily large offset and/or frequency jumps, yet after
      reachieving calibration will again report its offset to the internal
      PTP reference frame as 0.0 ± 0.0. To signal such 'timing shocks' to
      consumers, every timing source performing discontinuous changes in a
      way that breaks implicit synchronicity has to increase its
      continuity_index (with wraparound behaviour in the unlikely case of
      overflow).
    */
      continuity_index: null | VAPI.PTP.ContinuityIndex;
      speed: number;
      max_rel_acceleration: number;

      /**
      Current drift/offset estimates, referring to whatever reference frame
      the corresponding servo controller uses
    */
      current_estimate: null | VAPI.Servos.CurrentEstimate;

      /**
      counter values may be negative to indicate deviations beyond the
      holdover threshold
    */
      counters: VAPI.Servos.Counters;
      attempting_calibration_for: VScript.Duration;
    },
    _socket: VScript.VSocket,
  ): [
    VAPI.Servos.State,
    null | number,
    number,
    number,
    (
      | null
      | [
          [number, number, number, number],
          null | [number, number, number, number],
        ]
    ),
    [number, number, number, number, number, number, number],
    number,
  ] => [
    _x.state,
    _x.continuity_index,
    _x.speed,
    _x.max_rel_acceleration,
    _x.current_estimate === null
      ? null
      : VAPI.Servos.lower.CurrentEstimate(_x.current_estimate, _socket),
    VAPI.Servos.lower.Counters(_x.counters, _socket),
    VScript.VAPIHelpers.lowerNanoseconds(
      _x.attempting_calibration_for,
      _socket,
    ),
  ],
  Mode: (
    _x:
      | { variant: "LockToInput"; value: VAPI.Servos.ModeLockToInput }
      | { variant: "FreeRun"; value: VAPI.Servos.ModeFreeRun }
      | { variant: "Manual"; value: VAPI.Servos.ModeManual },
    _socket: VScript.VSocket,
  ): [0, []] | [1, [boolean]] | [2, [number, number]] => {
    switch (_x.variant) {
      case "LockToInput":
        return [0, VAPI.Servos.lower.ModeLockToInput(_x.value, _socket)];
      case "FreeRun":
        return [1, VAPI.Servos.lower.ModeFreeRun(_x.value, _socket)];
      case "Manual":
        return [2, VAPI.Servos.lower.ModeManual(_x.value, _socket)];
    }
  },
  OffsetThresholds: (
    _x: {
      rough_jump: VScript.Duration;
      holdover: VScript.Duration;
      convergence: VScript.Duration;
      inner_target_corridor: VScript.Duration;
    },
    _socket: VScript.VSocket,
  ): [number, number, number, number] => [
    VScript.VAPIHelpers.lowerSeconds(_x.rough_jump, _socket),
    VScript.VAPIHelpers.lowerSeconds(_x.holdover, _socket),
    VScript.VAPIHelpers.lowerSeconds(_x.convergence, _socket),
    VScript.VAPIHelpers.lowerSeconds(_x.inner_target_corridor, _socket),
  ],
  PLLParameters: (
    _x: {
      /**
      Min. relative clock period change per tick
    */
      min_drift_adjustment_step: number;

      /**
      Max. relative clock period change per tick
    */
      max_drift_adjustment_step: number;
      drift_growth_factor: number;
      stiffness: number;
      damping: number;
    },
    _socket: VScript.VSocket,
  ): [number, number, number, number, number] => [
    _x.min_drift_adjustment_step,
    _x.max_drift_adjustment_step,
    _x.drift_growth_factor,
    _x.stiffness,
    _x.damping,
  ],
  ParameterRegime: (
    _x: {
      pll: VAPI.Servos.PLLParameters;
      speed_limits: VAPI.Servos.ParameterRegimeSpeedLimits;
      offset_thresholds: VAPI.Servos.OffsetThresholds;
      drift_thresholds: VAPI.Servos.DriftThresholds;
    },
    _socket: VScript.VSocket,
  ): [
    [number, number, number, number, number],
    [number, number],
    [number, number, number, number],
    [number, number],
  ] => [
    VAPI.Servos.lower.PLLParameters(_x.pll, _socket),
    VAPI.Servos.lower.ParameterRegimeSpeedLimits(_x.speed_limits, _socket),
    VAPI.Servos.lower.OffsetThresholds(_x.offset_thresholds, _socket),
    VAPI.Servos.lower.DriftThresholds(_x.drift_thresholds, _socket),
  ],
  ActionReset: (_x: {}, _socket: VScript.VSocket): [] => [],
  Settings: (
    _x: {
      uncalibrated: VAPI.Servos.ParameterRegime;
      calibrated: VAPI.Servos.ParameterRegime;
      locking_policy: VAPI.Servos.LockingPolicy;
      counter_thresholds: VAPI.Servos.CounterThresholds;
      calibration_timeout: VScript.Duration;

      /**
      If set to `ResetAggressively`, clock controllers will not only clear
      their current estimates but reset their inputs as thoroughly as
      possible; e.g., a PTPClock resetting aggressively will cause all PTP
      agents currently running in Slave mode to reset their currently
      selected best masters and any other transient data they may hold
    */
      on_calibration_timeout: VAPI.Servos.OnCalibrationTimeout;
    },
    _socket: VScript.VSocket,
  ): [
    [
      [number, number, number, number, number],
      [number, number],
      [number, number, number, number],
      [number, number],
    ],
    [
      [number, number, number, number, number],
      [number, number],
      [number, number, number, number],
      [number, number],
    ],
    VAPI.Servos.LockingPolicy,
    [number, number],
    number,
    VAPI.Servos.OnCalibrationTimeout,
  ] => [
    VAPI.Servos.lower.ParameterRegime(_x.uncalibrated, _socket),
    VAPI.Servos.lower.ParameterRegime(_x.calibrated, _socket),
    _x.locking_policy,
    VAPI.Servos.lower.CounterThresholds(_x.counter_thresholds, _socket),
    VScript.VAPIHelpers.lowerNanoseconds(_x.calibration_timeout, _socket),
    _x.on_calibration_timeout,
  ],
  ActionSlew: (
    _x: { target_speed: number },
    _socket: VScript.VSocket,
  ): [number] => [_x.target_speed],
  ParameterRegimeSpeedLimits: (
    _x: { min: number; max: number },
    _socket: VScript.VSocket,
  ): [number, number] => [_x.min, _x.max],
} as const;
export type Action =
  | { variant: "Jump"; value: VAPI.Servos.ActionJump }
  | { variant: "Slew"; value: VAPI.Servos.ActionSlew }
  | { variant: "Reset"; value: VAPI.Servos.ActionReset };
export type CalibrationState = "Uncalibrated" | "Calibrated";
export interface CounterThresholds {
  promotion: number;
  demotion: number;
}
/**
  counter values may be negative to indicate deviations beyond the holdover
  threshold
*/
export interface Counters {
  missing_offset: VAPI.Primitives.SaturatingCounter16;
  missing_drift: VAPI.Primitives.SaturatingCounter16;
  bp_overall: VAPI.Primitives.SaturatingSignedCounter16;
  bp_offset: VAPI.Primitives.SaturatingSignedCounter16;
  bp_offset_errors: VAPI.Primitives.SaturatingSignedCounter16;
  bp_drift: VAPI.Primitives.SaturatingSignedCounter16;
  bp_drift_errors: VAPI.Primitives.SaturatingSignedCounter16;
}
/**
  Current drift/offset estimates, referring to whatever reference frame the
  corresponding servo controller uses
*/
export interface CurrentEstimate {
  offset: VAPI.Time.TimestampedOffset;
  drift: null | VAPI.Time.TimestampedDrift;
}
export type Direction = "Upwards" | "Downwards";
export interface DriftThresholds {
  holdover: number;
  convergence: number;
}
export interface ModeFreeRun {
  reset_drift: boolean;
}
export interface ActionJump {
  rough: boolean;
  delta_t: VScript.Duration;
}
export interface ModeLockToInput {}
export type LockingPolicy = "Locking" | "Dynamic";
export interface ModeManual {
  relative_speed: number;
  offset: VScript.Duration;
}
export interface Metrics {
  state: VAPI.Servos.State;

  /**
    Most clock control units continuously adjust their target's operating
    frequency until the time and/or frequency offset between source and
    target matches a user-defined value. These units require no data beyond
    frame rate, source type, frequency offset and offset.
    
    However, other clock operations implicitly guarantee synchronicity by
    rigidly linking their target's operating frequency to the source
    frequency. This implicit link may be broken when the timing source
    changes discontinuously. For example, an uncalibrated PTP clock may
    perform arbitrarily large offset and/or frequency jumps, yet after
    reachieving calibration will again report its offset to the internal PTP
    reference frame as 0.0 ± 0.0. To signal such 'timing shocks' to
    consumers, every timing source performing discontinuous changes in a way
    that breaks implicit synchronicity has to increase its continuity_index
    (with wraparound behaviour in the unlikely case of overflow).
  */
  continuity_index: null | VAPI.PTP.ContinuityIndex;
  speed: number;
  max_rel_acceleration: number;

  /**
    Current drift/offset estimates, referring to whatever reference frame the
    corresponding servo controller uses
  */
  current_estimate: null | VAPI.Servos.CurrentEstimate;

  /**
    counter values may be negative to indicate deviations beyond the holdover
    threshold
  */
  counters: VAPI.Servos.Counters;
  attempting_calibration_for: VScript.Duration;
}
export type Mode =
  | { variant: "LockToInput"; value: VAPI.Servos.ModeLockToInput }
  | { variant: "FreeRun"; value: VAPI.Servos.ModeFreeRun }
  | { variant: "Manual"; value: VAPI.Servos.ModeManual };
export interface OffsetThresholds {
  rough_jump: VScript.Duration;
  holdover: VScript.Duration;
  convergence: VScript.Duration;
  inner_target_corridor: VScript.Duration;
}
/**
  If set to `ResetAggressively`, clock controllers will not only clear their
  current estimates but reset their inputs as thoroughly as possible; e.g., a
  PTPClock resetting aggressively will cause all PTP agents currently running
  in Slave mode to reset their currently selected best masters and any other
  transient data they may hold
*/
export type OnCalibrationTimeout = "Reset" | "ResetAggressively";
export interface PLLParameters {
  /**
    Min. relative clock period change per tick
  */
  min_drift_adjustment_step: number;

  /**
    Max. relative clock period change per tick
  */
  max_drift_adjustment_step: number;
  drift_growth_factor: number;
  stiffness: number;
  damping: number;
}
export interface ParameterRegime {
  pll: VAPI.Servos.PLLParameters;
  speed_limits: VAPI.Servos.ParameterRegimeSpeedLimits;
  offset_thresholds: VAPI.Servos.OffsetThresholds;
  drift_thresholds: VAPI.Servos.DriftThresholds;
}
export type QualityAssessment = "Convergent" | "Normal" | "Divergent";
export interface ActionReset {}
export interface Settings {
  uncalibrated: VAPI.Servos.ParameterRegime;
  calibrated: VAPI.Servos.ParameterRegime;
  locking_policy: VAPI.Servos.LockingPolicy;
  counter_thresholds: VAPI.Servos.CounterThresholds;
  calibration_timeout: VScript.Duration;

  /**
    If set to `ResetAggressively`, clock controllers will not only clear
    their current estimates but reset their inputs as thoroughly as possible;
    e.g., a PTPClock resetting aggressively will cause all PTP agents
    currently running in Slave mode to reset their currently selected best
    masters and any other transient data they may hold
  */
  on_calibration_timeout: VAPI.Servos.OnCalibrationTimeout;
}
export interface ActionSlew {
  target_speed: number;
}
export type State = "Uncalibrated" | "Calibrated" | "FreeRun";
export interface ParameterRegimeSpeedLimits {
  min: number;
  max: number;
}
export const Enums = {
  State: ["Uncalibrated", "Calibrated", "FreeRun"] as State[],
  QualityAssessment: [
    "Convergent",
    "Normal",
    "Divergent",
  ] as QualityAssessment[],
  OnCalibrationTimeout: [
    "Reset",
    "ResetAggressively",
  ] as OnCalibrationTimeout[],
  LockingPolicy: ["Locking", "Dynamic"] as LockingPolicy[],
  Direction: ["Upwards", "Downwards"] as Direction[],
  CalibrationState: ["Uncalibrated", "Calibrated"] as CalibrationState[],
} as const;
