import { isTouchSupported } from "../helpers/touchSupport";
import { clamp } from "../helpers/number";

type SUPEREVENT = MouseEvent | TouchEvent;

export default class RangeSelector {
  public container: HTMLDivElement;
  protected filled: HTMLDivElement;
  protected seek: HTMLInputElement;

  public mousedown = false;

  private events: Partial<{
    //onMouseMove: ProgressLine['onMouseMove'],
    onMouseDown: RangeSelector['onMouseDown'],
    onMouseUp: RangeSelector['onMouseUp'],
    onScrub: (scrubTime: number) => void
  }> = {};

  protected decimals: number;

  constructor(protected step: number, protected value: number, protected min: number, protected max: number) {
    this.container = document.createElement('div');
    this.container.classList.add('progress-line');

    this.filled = document.createElement('div');
    this.filled.classList.add('progress-line__filled');

    const seek = this.seek = document.createElement('input');
    seek.classList.add('progress-line__seek');
    //seek.setAttribute('max', '0');
    seek.type = 'range';
    seek.step = '' + step;
    seek.min = '' + this.min;
    seek.max = '' + this.max;
    seek.value = '' + value;

    /* this.seek.addEventListener('change', (e) => {
      console.log('seek change', e);
    }); */

    if(value) {
      this.setProgress(value);
    }

    const stepStr = '' + this.step;
    const index = stepStr.indexOf('.');
    this.decimals = index === -1 ? 0 : stepStr.length - index - 1;

    //this.setListeners();

    this.container.append(this.filled, seek);
  }

  public setHandlers(events: RangeSelector['events']) {
    this.events = events;
  }

  onMouseMove = (e: SUPEREVENT) => {
    this.mousedown && this.scrub(e);
  };

  onMouseDown = (e: SUPEREVENT) => {
    this.scrub(e);
    this.mousedown = true;
    this.events?.onMouseDown && this.events.onMouseDown(e);
  };

  onMouseUp = (e: SUPEREVENT) => {
    this.mousedown = false;
    this.events?.onMouseUp && this.events.onMouseUp(e);
  };

  public setListeners() {
    this.container.addEventListener('mousemove', this.onMouseMove);
    this.container.addEventListener('mousedown', this.onMouseDown);
    this.container.addEventListener('mouseup', this.onMouseUp);

    if(isTouchSupported) {
      this.container.addEventListener('touchmove', this.onMouseMove, {passive: true});
      this.container.addEventListener('touchstart', this.onMouseDown, {passive: true});
      this.container.addEventListener('touchend', this.onMouseUp, {passive: true});
    }
  }

  public setProgress(value: number) {
    this.setFilled(value);
    this.seek.value = '' + value;
  }

  public setFilled(value: number) {
    let percents = (value - this.min) / (this.max - this.min);
    percents = clamp(percents, 0, 1);
    //console.log('setFilled', percents, value);
    this.filled.style.width = (percents * 100) + '%';
    //this.filled.style.transform = 'scaleX(' + scaleX + ')';
  }

  protected scrub(e: SUPEREVENT) {
    let offsetX: number;
    const rect = (e.target as HTMLElement).getBoundingClientRect();
    if(e instanceof MouseEvent) {
      offsetX = e.pageX - Math.round(rect.left);
    } else { // touch
      offsetX = e.targetTouches[0].pageX - Math.round(rect.left);
    }

    let value = this.min + (offsetX / Math.round(rect.width) * (this.max - this.min));

    if((value - this.min) < ((this.max - this.min) / 2)) {
      value -= this.step / 10;
    }
    
    //console.log('scrub value:', value, this.decimals, offsetX, rect.width, e);
    value = +value.toFixed(this.decimals);
    //const dotIndex = ('' + value).indexOf('.');
    //value = +('' + value).slice(0, this.decimals ? dotIndex + this.decimals : dotIndex);

    value = clamp(value, this.min, this.max);

    this.setFilled(value);

    this.events?.onScrub && this.events.onScrub(value);
    return value;
  }

  public removeListeners() {
    this.container.removeEventListener('mousemove', this.onMouseMove);
    this.container.removeEventListener('mousedown', this.onMouseDown);
    this.container.removeEventListener('mouseup', this.onMouseUp);

    if(isTouchSupported) {
      this.container.removeEventListener('touchmove', this.onMouseMove);
      this.container.removeEventListener('touchstart', this.onMouseDown);
      this.container.removeEventListener('touchend', this.onMouseUp);
    }

    this.events = {};
  }
}