// DateCounterClass allows us to add several counters to the input, and use them seperately.
// For examele, we have a DayCounter, MonthCounter and YearCounter, which can each separately navigate
// between different ranges.
export class DateCounter {
  #data = Object.freeze([]);

  constructor({ id, min, max, placeholder }, onChange) {
    this.id = id;
    this.min = min;
    this.max = max;
    this.placeholder = placeholder;
    this.onChange = onChange;
  }

  get data() {
    return this.#data;
  }

  set data(val) {
    this.#data = Object.freeze(val);
    this.onChange?.();
  }

  get #initialNumValue() {
    return this.data.length ? this.numberValue : 0;
  }

  get numberValue() {
    return Number(this.stringValue);
  }

  get stringValue() {
    return (this.data.join('') || this.placeholder).padStart(this.length, '0');
  }

  get isFull() {
    return this.numberValue * 10 > this.max || this.data.length === this.length;
  }

  get isEmpty() {
    return this.stringValue === this.placeholder;
  }

  get length() {
    return this.max.toString().length;
  }

  set(val) {
    this.data = val.toString().split('');
  }

  add(num) {
    // use local var to avoid triggering onChange
    let data = this.data;

    data = [...data, num];

    // we need to re-evaluate the number value
    const numVal = Number(data.join(''));

    if (numVal > this.max) {
      data = [num];
    } else if (this.length < data.length) {
      data = data.slice(1, data.length);
    }

    this.data = data;

    return num;
  }

  del() {
    if (!this.data.filter((d) => d !== '0').filter(Boolean).length) {
      this.data = [];
    } else {
      this.data = this.data.slice(0, this.data.length - 1);
    }
  }

  clear() {
    this.data = [];
  }

  inc(gap) {
    this.replaceValue(
      this.#initialNumValue < this.max
        ? Math.max(this.#initialNumValue + (gap || 1), this.min)
        : this.min
    );
  }

  dec(gap) {
    this.replaceValue(
      this.#initialNumValue > this.min
        ? Math.min(this.#initialNumValue - (gap || 1), this.max)
        : this.max
    );
  }

  isInRange(val) {
    return val >= this.min && val <= this.max;
  }

  replaceValue(val) {
    if (this.isInRange(val)) {
      this.data = val.toString().padStart(this.length, 0).split('');
    }
  }

  setMin(val) {
    this.min = Number(val);
  }

  setMax(val) {
    this.max = Number(val);
  }
}
