class ErrorHandle {
#validator
#type
#onError
#countion
#setVal
#rollback
#keep = false
#handle

  constructor({validator, type, onError, countion, setVal, rollback}) {
    this.#validator = validator;
    this.#type = type;
    this.#onError = onError;
    this.#countion = countion;
    this.#setVal = setVal;
    this.#rollback = rollback;
  }

  error(element, index) {
    if (this.#keep && this.#handle) {
      this.#setVal();
    } else {
      this.#onError(this.#type, element, index, (handle, keep) => {
        if (keep) {
          this.#keep = true;
          this.#handle = handle;
        }
        if (handle) {
          this.#setVal(element, index);
        }
      }, this.#rollback);
    }
  }
}

export default function Iterator({data, setVal, onProgress, rules = []}) {
  let current = 0;
  let marks = [];

  function rollback() {
    marks.forEach(
        element => {setVal(element.key, element.oldValue, element.newValue)})
  }

  let errorHandles = [];

  function getPromise() {
    return new Promise((resolve, reject) => {
      rules.forEach(element => {
        errorHandles.push(new ErrorHandle({
          validator: element.validator,
          type: element.type,
          countion: getPromise(),
          setVal: resolve,
          onError: reject,
          rollback
        }));
      });

      for (; current < data.length; current++) {
        onProgress && onProgress(current, data.length);
        const element = data[current];

        errorHandles.forEach(errorHandle => {
          if (errorHandle.validator(element, current)) {
            errorHandle.error(element, current);
            return;
          }
        });

        resolve(element);
        this.current++;
      }

      resolve();
    })
  }

  return getPromise();
}
