class Stages{
  #data;

  #trigger;

  #wrapper;

  #modal;

  #statusLine = [];

  #gridSize;

  #waysArr = []

  #topIndex = 1;

  #fromToArr = [];

  static CLASS_NAME = 'stages__';

  constructor(trigger, data){
    this.#data = data;
    this.#trigger = trigger;
  }

  init(){
    this.#trigger.click(() => this.buildModal());
  }

  buildModal(){
    this.#wrapper = h.div('chooser-wrapper').appendToBody();
    this.#modal = h.div('remote-chooser stages__modal').appendTo(this.#wrapper);

    h.div('close-date-chooser').appendTo(this.#modal).click(() => this.close());
    this.build();
  }

  close(){
    this.#wrapper.text(null).remove();
    this.#modal.text(null).remove();
    this.#gridSize = 0;
    this.#statusLine = [];
    this.#topIndex = 1;
    this.#waysArr = [];
    this.#fromToArr = [];
  }

  build(){
    var first = this.#data.filter((el) => !el.prevStatus)[0];

    this.getStatusLine(first, () => {
      this.#gridSize = this.#statusLine.length + this.#statusLine.length - 1;

      if(this.#gridSize < 5) this.#gridSize = 5;

      var lineLenght  = this.#waysArr.length * 2;

      if(lineLenght < 5 ) lineLenght = 5;
      if(lineLenght > 10 ) lineLenght = 10;

      var center = Math.ceil(lineLenght / 2);
      this.#modal.style().gridRepeatColumn(this.#gridSize + 1, '1fr').gridRepeatRow(lineLenght,'1fr');

      _.each(this.#statusLine, (el, i) => {

      if(el && el.currentStatus) {
        this.getDivItem(el.currentStatus).appendTo(this.#modal).id(el.currentStatus.id).style().gridRowStart(center)
      }
        
        
        if(i != this.#statusLine.length - 1){
          h.div('stages__line').appendTo(this.#modal).style().gridRowStart(center);
        }   
      })

      this.drawAllAnotherPrev();
      this.buildLinesFromTo();
    }) 
  }

  buildLinesFromTo(){
    _.each(this.#fromToArr, (el) => {
      var toDiv = h.fromId(el.statusTo.id);

      if(toDiv) {
        var posFrom = {
          top: el.div.getOffsetTop(),
          left: el.div.getOffsetLeft(),
          width: el.div.getRect().width,
          height: el.div.getRect().height,
        }
        var posTo= {
          top: toDiv.getOffsetTop(),
          left: toDiv.getOffsetLeft(),
          width: el.div.getRect().width,
          height: el.div.getRect().height,
        }
  
        var isBottomDiv = el.div.getData('pos') == 'bottom';
  
        var width = posFrom.left - posTo.left - posTo.width * 2.5;
        var left = posTo.left + posTo.width * 2.5;
        var top = posFrom.top+posFrom.height/2;
  
        var arrow = h.div(Stages.CLASS_NAME + 'red-line').appendTo(this.#modal).height(posFrom.height).width(width).style().absolute()
        .top(top).left(left).horizontMirror();
  
        var arrowTo = this.buildVerticalArrowTo(left, top, posFrom.height)
  
        if(isBottomDiv) {
          arrow.mirror().top(posFrom.top - posFrom.height / 2);
          arrowTo = this.buildVerticalArrowTo(left, posFrom.top - posFrom.height / 4 - 20, posFrom.height).verticalMirror()
        }
        arrowTo.back().appendTo(this.#modal);
      }
      
    })
  }

  buildVerticalArrowTo(left, top, height){
    return h.div(Stages.CLASS_NAME + 'red-arrow').height(height).style().absolute().left(left).top(top)
  }

  drawAllAnotherPrev(){
    var pos = {
      top: '',
      left: '',
      height: ''
    }
    _.each(this.#waysArr, ((way, index) => {
      var currentTop;
      var currentLeft = 0;
      var topPlusLenght = 60;
      var div;
      var prevInLine = false;
      _.each(way, (stat, i) => {
        var isTop = index % 2 == 0;
        if(i == 0) {
          div = (h.fromId(stat.id));
          pos = {
            top: div.getOffsetTop(),
            left: div.getOffsetLeft(),
            height: div.getRect().height,
            width: div.getRect().width,
          }
        } else if (i == 1) {
          if(!this.isStatusInLine(stat, div)){
            prevInLine = true;
            if(index != 1 && index !=0 ){
              topPlusLenght = 10;
            }
            var top = pos.top - pos.height * this.#topIndex - topPlusLenght; 
            if(!isTop) top = pos.top + pos.height * this.#topIndex + topPlusLenght;
            currentTop = top;
            var left = pos.left;
            currentLeft = left;
            var item = this.getDivItem(stat, false).id(stat.id + '_index_'+ i + '_' + index).width(pos.width).style().absolute().top(top).left(left).back()
            .appendTo(this.#modal);
            if(!isTop) item.setData('pos', 'bottom')
            if(i == way.length - 2) {
              this.#fromToArr.push({div: item, statusTo: way[i + 1]});
            }

            var lineTop = top + pos.height;
            var lineHeight = pos.top - top - pos.height;
  
            var lineLeft = left + pos.width/2;
            if(!isTop) {
              lineHeight = top -  pos.top - pos.height;
              lineTop = pos.top + pos.height;
            }
            var line = h.div(Stages.CLASS_NAME + 'arrow').height(lineHeight).appendTo(this.#modal)
            .style().absolute().top(lineTop).left(lineLeft);
            if(!isTop) line.back().cl('rotated_180');
          } else this.getLineStatusFrom(div, stat, isTop)
          
        } else {
          if(!this.isStatusInLine(stat) && prevInLine){
            
            var top = currentTop; 
            var left = currentLeft - pos.width * 2;
            currentLeft = left;
            this.getDivItem(stat, false).width(pos.width).id(stat.id + '_index_'+ i + '_' + index).style().absolute().top(top).left(left).back()
            .appendTo(this.#modal);

            if(i == way.length - 2) {
              this.#fromToArr.push({div: item, statusTo: way[i + 1]});
            }

            var lineTop = top + pos.height / 2;
  
            var lineLeft = left + pos.width;
              
            h.div(Stages.CLASS_NAME + 'arrow-gorizont').width(pos.width).appendTo(this.#modal).style()
              .absolute().top(lineTop).left(lineLeft);
          }  
        }

        if(!isTop && i == way.length - 1) this.#topIndex++;
      })
    }))
  }

  isStatusInLine(status){
    var currentStatus = (this.#statusLine).filter((el) => el.currentStatus.id === status.id)[0];
    if(_.isNull(currentStatus)){
      return false
    } else {
      return true;
    }
  }

  getLineStatusFrom(fromDiv, status, isTop){
    var toDiv = h.fromId(status.id);

    var posFrom = {
      top: fromDiv.getOffsetTop(),
      left: fromDiv.getOffsetLeft(),
      width: fromDiv.getRect().width,
      height: fromDiv.getRect().height,
    }
    var posTo= {
      top: toDiv.getOffsetTop(),
      left: toDiv.getOffsetLeft(),
      width: toDiv.getRect().width,
      height: toDiv.getRect().height,
    }

    var width = posFrom.left - posTo.left - posTo.width / 2;

    var top = posFrom.top - posFrom.height * 1.3;

    var line = h.div(Stages.CLASS_NAME + 'red-line').appendTo(this.#modal).height(posFrom.height).width(width).style().absolute()
    .top(top).left(posTo.left + posTo.width).rotateDeg(180);

    var topLineWidth = (posFrom.top - (posFrom.top - posFrom.height * 1.3)) / 4;

    var leftForTopLine = posTo.left + posTo.width + width;

    var topLine = h.div(Stages.CLASS_NAME + 'red-line-top').appendTo(this.#modal).height(topLineWidth).style().absolute()
    .top(top + posFrom.height).left(leftForTopLine);

    var bottomLine = h.div(Stages.CLASS_NAME + 'red-arrow').appendTo(this.#modal).height(topLineWidth).style().absolute()
    .top(top + posFrom.height).rotateDeg(43).left(posTo.left + posTo.width - 15);

    
    if(!isTop) {
      line.horizontMirror().top(posFrom.top - posFrom.height / 2)
    }
  }

  buildArrayForNextSteps(callback){
    const arrayForNextStatus = (this.#waysArr).map((el) => {
      return el[1]
    })

    var arrawFowDraw = []

    _.each(arrayForNextStatus, (el) => {
      var statusFull = this.#data.filter((it) => it.currentStatus.id == el.id)[0];

      if(statusFull && statusFull.nexStatus){
        arrawFowDraw.push({
          next: statusFull.nexStatus,
          elements: document.querySelectorAll(`[data-id="${el.id}"]`)
        })
      }
      
    })
    var filtredArray = arrawFowDraw.filter((item, index) => {
      return JSON.stringify(arrawFowDraw[index - 1]) != JSON.stringify(item) 
  });
    callback(filtredArray, this);
  }

  getDivItem(status, needId = true){

    var border = "4px solid " + status.color;

    var item = h.div(Stages.CLASS_NAME + 'item')
      .add(h.img(status.icon, Environment.defaultIconSize).width(20).height(20))
      .add(h.div(Stages.CLASS_NAME + 'name').text(status.name, false)).style().border(border).back();

    if(needId) {
      item.id(status.id)
    }

    return item;
  }

  getStatusLine(prev, callback){ 
    var current = this.#data.filter((el) => el.currentStatus.id == prev.nexStatus.id)[0];
    
    if(_.isNull(prev.prevStatus)){
      this.#statusLine.push(prev);
    }

    if(current) {
      this.#statusLine.push(current);
    }

    if(!current || _.isNull(current.nexStatus)) {

      var anotherWays = this.#statusLine.filter((el, i) => {
        if(el.prevStatus) {
          return  this.#statusLine[i - 1] && this.#statusLine[i - 1].currentStatus.id !== el.prevStatus.id
        } else return false;
      })

      _.each(anotherWays, (el) => {
        this.getAllAnotherPrev(el, [])
      })
      callback();

      return;
    }

    this.getStatusLine(current, callback);
  }


  getAllAnotherPrev(current, arr){
    var prev = this.#data.filter((el) => el.currentStatus.id == current.prevStatus.id)[0];

    var currentArr = arr;

    if(!prev){
      currentArr.push(current.currentStatus);
      currentArr.push(current.prevStatus);
    } else {
      currentArr.push(current.currentStatus);
    }
    
    if(_.isNull(prev) || _.isNull(prev.prevStatus)) {
      if(prev) currentArr.push(prev.currentStatus);
      this.#waysArr.push(currentArr);
      return currentArr;
    }

    this.getAllAnotherPrev(prev, currentArr);
  }
}
