
import { panForward, panLeft, panRight, startAddresses, tiltDown, tiltUp } from './stage'
import { Pattern, PatternOutput, RenderUpdate } from './proto';
import { MovingHeadState } from 'rust_native_module';
import { Tuple4 } from './types';
import { hsl2rgb, clamp, rescale } from './util';

const HSL_CYCLE_LENGTH: number = 7; // seconds
const MOVEMENT_CYCLE_LENGTH: number = 0.5; // seconds?
const THRESHOLD: number = 1.5;

const panBounds: Tuple4<[number, number]> = [
  [panLeft, panRight],
  [panLeft, panRight],
  [panLeft, panRight],
  [panLeft, panRight],
];

const tiltBound: [number, number] = [tiltDown, tiltUp];

export class HSLRandomMovementPattern implements Pattern {

  brightness: number;
  targets: Tuple4<[number, number]>;
  lastUpdate: number;

  constructor() {
    this.brightness = 0;
    this.targets = [
      [panLeft, tiltUp],
      [panForward, tiltUp],
      [panForward, tiltUp],
      [panRight, tiltUp],
    ]
    this.lastUpdate = 0;
  }

  render(update: RenderUpdate): PatternOutput {

    // color

    const t = update.absolute;
    const h = 360 * ((t % HSL_CYCLE_LENGTH) / HSL_CYCLE_LENGTH);
    const s = 1;
    const v = 0.5;

    const [r, g, b] = hsl2rgb(h, s, v);
    const rgbw: Tuple4<number> = [
      Math.round(r * 255),
      Math.round(g * 255),
      Math.round(b * 255),
      0
    ];

    // brightness

    this.brightness = update.bassVolume > THRESHOLD
      ? 1
      : 0.75 * this.brightness;

    // movement

    if (t - this.lastUpdate > MOVEMENT_CYCLE_LENGTH) {

      this.lastUpdate = t;

      for (let index in [0, 1, 2, 3]) {

        const bound = panBounds[index];

        const pan = rescale(Math.random(), { to: bound });
        const tilt = clamp(Math.acos(Math.random()), tiltBound);

        this.targets[index] = [pan, tilt];
      }
    }

    return startAddresses.map((startAddress, index) => {
      const [pan, tilt] = this.targets[index];

      let state: MovingHeadState = {
        startAddress: startAddress,
        pan: pan,
        tilt: tilt,
        brightness: {
          type: 'dimmer',
          value: 0.2 + 0.8 * this.brightness,
        },
        rgbw: rgbw,
        speed: 1,
        reset: false
      }

      return state;

    }) as PatternOutput;
  }
}
