import {Component, ElementRef, EventEmitter, HostListener, Input, OnChanges, OnDestroy, OnInit, Output, ViewChild} from '@angular/core';
import {Subject} from 'rxjs';
import {debounceTime} from 'rxjs/operators';
import {EditorItem, HotZoneItem, Label, MySprite} from './Unit';
import TWEEN from '@tweenjs/tween.js';


@Component({
  selector: 'app-custom-hot-zone',
  templateUrl: './custom-hot-zone.component.html',
  styleUrls: ['./custom-hot-zone.component.scss']
})
export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {




  _bgItem = null;

  @Input()
  set bgItem(v) {
    this._bgItem = v;

    this.init();
  }
  get bgItem() {
    return this._bgItem;
  }

  @Input()
  imgItemArr = null;

  @Input()
  hotZoneItemArr = null;



  @Input()
  hotZoneArr = null;


  @Output()
  save = new EventEmitter();

  @ViewChild('canvas') canvas: ElementRef;
  @ViewChild('wrap') wrap: ElementRef;
  @HostListener('window:resize', ['$event'])

  canvasWidth = 1280;
  canvasHeight = 720;

  canvasBaseW = 1280;
  canvasBaseH = 720;
  mapScale = 1;

  ctx;
  mx;
  my; // 点击坐标


  // 资源
  // rawImages = new Map(res);

  // 声音
  bgAudio = new Audio();


  images = new Map();

  animationId: any;
  winResizeEventStream = new Subject();

  canvasLeft;
  canvasTop;

  renderArr;

  imgArr = [];

  oldPos;



  curItem;
  bg: MySprite;
  changeSizeFlag = false;
  changeTopSizeFlag = false;
  changeRightSizeFlag = false;



  constructor() {
  }



  onResize(event) {
    this.winResizeEventStream.next();
  }


  ngOnInit() {

    this.initListener();

    // this.init();
    this.update();

  }

  ngOnDestroy() {
    window.cancelAnimationFrame(this.animationId);
  }


  ngOnChanges() {

  }



  onBackgroundUploadSuccess(e) {
    console.log('e: ', e);
    this.bgItem.url = e.url;
    this.refreshBackground();
  }

  refreshBackground(callBack = null) {

    if (!this.bg) {
      this.bg = new MySprite(this.ctx);
      this.renderArr.push(this.bg);
    }

    const bg = this.bg;
    if (this.bgItem.url) {

      bg.load(this.bgItem.url).then(() => {
        const rate1 = this.canvasWidth / bg.width;
        const rate2 = this.canvasHeight / bg.height;

        const rate = Math.min(rate1, rate2);
        bg.setScaleXY(rate);


        bg.x = this.canvasWidth / 2;
        bg.y = this.canvasHeight / 2;

        if (callBack) {
          callBack();
        }
      });
    }

  }


  addBtnClick() {
    // this.imgArr.push({});
    // this.hotZoneArr.push({});

    const item = this.getHotZoneItem();
    this.hotZoneArr.push(item);

    this.refreshHotZoneId();

    console.log('hotZoneArr:', this.hotZoneArr);
  }

  onImgUploadSuccessByImg(e, img) {
    img.pic_url = e.url;
    this.refreshImage (img);
  }

  refreshImage(img) {

    this.hideAllLineDash();

    img.picItem = this.getPicItem(img);

    this.refreshImageId();

  }


  refreshHotZoneId() {
    for (let i = 0; i < this.hotZoneArr.length; i++) {
      this.hotZoneArr[i].index = i;

      if (this.hotZoneArr[i]) {
        this.hotZoneArr[i].text = 'item-' + (i + 1);

      }
    }
  }


  refreshImageId() {
    for (let i = 0; i < this.imgArr.length; i++) {
      this.imgArr[i].id = i;

      if (this.imgArr[i].picItem) {
        this.imgArr[i].picItem.text = 'Image-' + (i + 1);
      }
    }

  }

  getHotZoneItem( saveData = null) {


    const itemW = 200;
    const itemH = 200;
    const item = new HotZoneItem(this.ctx);
    item.setSize(itemW, itemH);
    item.anchorX = 0.5;
    item.anchorY = 0.5;

    item.x = this.canvasWidth / 2;
    item.y = this.canvasHeight / 2;

    if (saveData) {

      const saveRect = saveData.rect;
      item.scaleX = saveRect.width / item.width;
      item.scaleY = saveRect.height / item.height;
      item.x = saveRect.x + saveRect.width / 2 ;
      item.y = saveRect.y + saveRect.height / 2;

    }

    item.showLineDash();


    return item;
  }


  getPicItem(img, saveData = null) {


    const item = new EditorItem(this.ctx);
    item.load(img.pic_url).then( img => {

      let maxW, maxH;
      if (this.bg) {
        maxW = this.bg.width * this.bg.scaleX;
        maxH = this.bg.height * this.bg.scaleY;
      } else {
        maxW = this.canvasWidth;
        maxH = this.canvasHeight;
      }

      let scaleX = maxW / 3 / item.width;
      let scaleY = maxH / 3 / item.height;

      if (item.height * scaleX < this.canvasHeight) {
        item.setScaleXY(scaleX);
      } else {
        item.setScaleXY(scaleY);
      }
      item.x = this.canvasWidth / 2;
      item.y = this.canvasHeight / 2;

      if (saveData) {

        const saveRect = saveData.rect;
        item.setScaleXY(saveRect.width / item.width);
        item.x = saveRect.x + saveRect.width / 2 ;
        item.y = saveRect.y + saveRect.height / 2;

      } else {
        item.showLineDash();
      }

    });
    return item;
  }


  onAudioUploadSuccessByImg(e, img) {
    img.audio_url = e.url;
  }

  deleteItem(e, i) {
    // this.imgArr.splice(i , 1);
    // this.refreshImageId();

    this.hotZoneArr.splice(i, 1);
    this.refreshHotZoneId();
  }







  init() {

    this.initData();
    this.initCtx();

    this.initItem();
  }

  initItem() {
    if (!this.bgItem) {
      this.bgItem = {};
    } else {
      this.refreshBackground(() => {

        // if (!this.imgItemArr) {
        //   this.imgItemArr = [];
        // } else {
        //   this.initImgArr();
        // }

        // console.log('aaaaa');

        if (!this.hotZoneItemArr) {
          this.hotZoneItemArr = [];
        } else {
          this.initHotZoneArr();
        }

      });
    }

  }

  initHotZoneArr() {

    // console.log('this.hotZoneArr: ', this.hotZoneArr);
    let curBgRect;
    if (this.bg) {
      curBgRect = this.bg.getBoundingBox();
    } else {
      curBgRect = {x: 0, y: 0, width: this.canvasWidth, height: this.canvasHeight};
    }

    let oldBgRect = this.bgItem.rect;
    if (!oldBgRect) {
      oldBgRect = curBgRect;
    }

    const rate = curBgRect.width / oldBgRect.width;

    console.log('rate: ', rate);

    this.hotZoneArr = [];
    const arr = this.hotZoneItemArr.concat();
    for (let i = 0; i < arr.length; i++) {

      const data = JSON.parse(JSON.stringify(arr[i]));
      // const img = {pic_url: data.pic_url};

      data.rect.x *= rate;
      data.rect.y *= rate;
      data.rect.width *= rate;
      data.rect.height *= rate;

      data.rect.x += curBgRect.x;
      data.rect.y += curBgRect.y;

      // img['picItem'] = this.getPicItem(img, data);
      // img['audio_url'] = arr[i].audio_url;
      // this.imgArr.push(img);

      const item = this.getHotZoneItem( data);
      console.log('item: ', item);
      this.hotZoneArr.push(item);

    }

    this.refreshHotZoneId();
    // this.refreshImageId();

  }




  initImgArr() {

    console.log('this.imgItemArr: ', this.imgItemArr);
    let curBgRect;
    if (this.bg) {
      curBgRect = this.bg.getBoundingBox();
    } else {
      curBgRect = {x: 0, y: 0, width: this.canvasWidth, height: this.canvasHeight};
    }

    let oldBgRect = this.bgItem.rect;
    if (!oldBgRect) {
      oldBgRect = curBgRect;
    }

    const rate = curBgRect.width / oldBgRect.width;

    console.log('rate: ', rate);

    this.imgArr = [];
    const arr = this.imgItemArr.concat();
    for (let i = 0; i < arr.length; i++) {

      const data = JSON.parse(JSON.stringify(arr[i]));
      const img = {pic_url: data.pic_url};

      data.rect.x *= rate;
      data.rect.y *= rate;
      data.rect.width *= rate;
      data.rect.height *= rate;

      data.rect.x += curBgRect.x;
      data.rect.y += curBgRect.y;

      img['picItem'] = this.getPicItem(img, data);
      img['audio_url'] = arr[i].audio_url;
      this.imgArr.push(img);
    }
    this.refreshImageId();
  }


  initData() {

    this.canvasWidth = this.wrap.nativeElement.clientWidth;
    this.canvasHeight = this.wrap.nativeElement.clientHeight;
    this.mapScale = this.canvasWidth / this.canvasBaseW;
    this.renderArr = [];
    this.bg = null;

    this.imgArr = [];
    this.hotZoneArr = [];
  }

  initCtx() {
    this.ctx = this.canvas.nativeElement.getContext('2d');
    this.canvas.nativeElement.width = this.canvasWidth;
    this.canvas.nativeElement.height = this.canvasHeight;
  }


  mapDown(event) {

    this.oldPos = {x: this.mx, y: this.my};

    const arr = this.hotZoneArr;

    for (let i = arr.length - 1; i >= 0 ; i--) {
      const item = arr[i];

      if (item) {
        if (this.checkClickTarget(item)) {

          if (item.lineDashFlag && this.checkClickTarget(item.arrow)) {
            this.changeItemSize(item);
          } else if (item.lineDashFlag && this.checkClickTarget(item.arrowTop)) {
            this.changeItemTopSize(item);
          } else if (item.lineDashFlag && this.checkClickTarget(item.arrowRight)) {
            this.changeItemRightSize(item);
          } else {
            this.changeCurItem(item);
          }
          return;
        }
      }
    }


    // this.hideAllLineDash();
  }

  mapMove(event) {
    if (!this.curItem) { return; }

    if (this.changeSizeFlag) {
      this.changeSize();

    } else if (this.changeTopSizeFlag) {
      this.changeTopSize();

    } else if (this.changeRightSizeFlag) {
      this.changeRightSize();

    } else {

      const addX = this.mx - this.oldPos.x;
      const addY = this.my - this.oldPos.y;
      this.curItem.x += addX;
      this.curItem.y += addY;
    }

    this.oldPos = {x: this.mx, y: this.my};
  }

  mapUp(event) {
    this.curItem = null;
    this.changeSizeFlag = false;
    this.changeTopSizeFlag = false;
    this.changeRightSizeFlag = false;
  }




  changeSize() {
    const rect = this.curItem.getBoundingBox();

    let lenW = ( this.mx - (rect.x + rect.width / 2) ) * 2;
    let lenH = ( (rect.y + rect.height / 2) - this.my ) * 2;


    let minLen = 20;
    let s;
    if (lenW < lenH) {
      if (lenW < minLen) {
        lenW = minLen;
      }
      s = lenW / this.curItem.width;

    } else {
      if (lenH < minLen) {
        lenH = minLen;
      }
      s = lenH / this.curItem.height;
    }


    // console.log('s: ', s);
    this.curItem.setScaleXY(s);
    this.curItem.refreshLabelScale();
  }


  changeTopSize() {
    const rect = this.curItem.getBoundingBox();

    // let lenW = ( this.mx - (rect.x + rect.width / 2) ) * 2;
    let lenH = ( (rect.y + rect.height / 2) - this.my ) * 2;


    let minLen = 20;
    let s;
    // if (lenW < lenH) {
    //   if (lenW < minLen) {
    //     lenW = minLen;
    //   }
    //   s = lenW / this.curItem.width;
    //
    // } else {
      if (lenH < minLen) {
        lenH = minLen;
      }
      s = lenH / this.curItem.height;
    // }


    // console.log('s: ', s);
    this.curItem.scaleY = s;
    this.curItem.refreshLabelScale();
  }

  changeRightSize() {
    const rect = this.curItem.getBoundingBox();

    let lenW = ( this.mx - (rect.x + rect.width / 2) ) * 2;
    // let lenH = ( (rect.y + rect.height / 2) - this.my ) * 2;

    let minLen = 20;
    let s;
    if (lenW < minLen) {
      lenW = minLen;
    }
    s = lenW / this.curItem.width;

    this.curItem.scaleX = s;
    this.curItem.refreshLabelScale();
  }

  changeItemSize(item) {
    this.curItem = item;
    this.changeSizeFlag = true;
  }

  changeItemTopSize(item) {
    this.curItem = item;
    this.changeTopSizeFlag = true;
  }

  changeItemRightSize(item) {
    this.curItem = item;
    this.changeRightSizeFlag = true;
  }

  changeCurItem(item) {

    this.hideAllLineDash();

    this.curItem = item;
    this.curItem.showLineDash();
  }

  hideAllLineDash() {

    for (let i = 0; i < this.imgArr.length; i++) {
      if (this.imgArr[i].picItem) {
        this.imgArr[i].picItem.hideLineDash();
      }
    }
  }


  update() {



    this.animationId = window.requestAnimationFrame(this.update.bind(this));
    // 清除画布内容
    this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);

    for (let i = 0; i < this.renderArr.length; i++) {
      this.renderArr[i].update(this);
    }

    // for (let i = 0; i < this.imgArr.length; i++) {
    //   const picItem = this.imgArr[i].picItem;
    //   if (picItem) {
    //     picItem.update(this);
    //   }
    // }

    this.updateArr(this.hotZoneArr);


    TWEEN.update();
  }

  updateArr(arr) {
    if (arr) {
      for (let i = 0; i < arr.length; i++) {
        arr[i].update();
      }
    }
  }



  renderAfterResize() {
    this.canvasWidth = this.wrap.nativeElement.clientWidth;
    this.canvasHeight = this.wrap.nativeElement.clientHeight;
    this.init();
  }

  initListener() {

    this.winResizeEventStream
      .pipe(debounceTime(500))
      .subscribe(data => {
        this.renderAfterResize();
      });

    if (this.IsPC()) {

      this.canvas.nativeElement.addEventListener('mousedown', (event) => {
        setMxMyByMouse(event);
        this.mapDown(event);
      });

      this.canvas.nativeElement.addEventListener('mousemove', (event) => {
        setMxMyByMouse(event);
        this.mapMove(event);
      });

      this.canvas.nativeElement.addEventListener('mouseup', (event) => {
        setMxMyByMouse(event);
        this.mapUp(event);
      });

      const setMxMyByMouse = (event) => {
        this.mx = event.offsetX;
        this.my = event.offsetY;
      };

    } else {

      this.canvas.nativeElement.addEventListener('touchstart', (event) => {
        setMxMyByTouch(event);
        this.mapDown(event);
      });

      this.canvas.nativeElement.addEventListener('touchmove', (event) => {
        setMxMyByTouch(event);
        this.mapMove(event);
      });

      this.canvas.nativeElement.addEventListener('touchend', (event) => {
        setMxMyByTouch(event);
        this.mapUp(event);
      });

      this.canvas.nativeElement.addEventListener('touchcancel', (event) => {
        setMxMyByTouch(event);
        this.mapUp(event);
      });


      const setMxMyByTouch = (event) => {
        if (event.touches.length <= 0) {
          return;
        }

        if (this.canvasLeft == null) {
          setParentOffset();
        }

        this.mx = event.touches[0].pageX - this.canvasLeft;
        this.my = event.touches[0].pageY - this.canvasTop;
      };


      const setParentOffset = () => {

        const rect = this.canvas.nativeElement.getBoundingClientRect();
        this.canvasLeft = rect.left;
        this.canvasTop = rect.top;
      };
    }
  }

  IsPC() {
    if (window['ELECTRON']) {
      return false; // 封装客户端标记
    }
    if (document.body.ontouchstart !== undefined) {
      return false;
    } else {
      return true;
    }
  }


  checkClickTarget(target) {

    const rect = target.getBoundingBox();
    if (this.checkPointInRect(this.mx, this.my, rect)) {
      return true;
    }
    return false;
  }

  checkPointInRect(x, y, rect) {
    if (x >= rect.x && x <= rect.x + rect.width) {
      if (y >= rect.y && y <= rect.y + rect.height) {
        return true;
      }
    }
    return false;
  }


  saveClick() {
    const bgItem = this.bgItem;
    if (this.bg) {
      bgItem['rect'] = this.bg.getBoundingBox();
    } else {
      bgItem['rect'] = {x: 0, y: 0, width: Math.round(this.canvasWidth * 100) / 100, height: Math.round(this.canvasHeight * 100) / 100};
    }



    // const imgItemArr = [];
    // const imgArr = this.imgArr;
    // for (let i = 0; i < imgArr.length; i++) {
    //
    //   const imgItem = {
    //     id: imgArr[i].id,
    //     pic_url: imgArr[i].pic_url,
    //     audio_url: imgArr[i].audio_url,
    //   };
    //   if (imgArr[i].picItem) {
    //     imgItem['rect'] = imgArr[i].picItem.getBoundingBox();
    //     imgItem['rect'].x -= bgItem['rect'].x;
    //     imgItem['rect'].y -= bgItem['rect'].y;
    //   }
    //   imgItemArr.push(imgItem);
    // }


    const hotZoneItemArr = [];
    const hotZoneArr = this.hotZoneArr;
    for (let i = 0; i < hotZoneArr.length; i++) {

      const hotZoneItem = {
        index: hotZoneArr[i].index,
      };
      hotZoneItem['rect'] = hotZoneArr[i].getBoundingBox();
      hotZoneItem['rect'].x = Math.round( (hotZoneItem['rect'].x - bgItem['rect'].x) * 100) / 100;
      hotZoneItem['rect'].y = Math.round( (hotZoneItem['rect'].y - bgItem['rect'].y) * 100) / 100;
      hotZoneItem['rect'].width = Math.round( (hotZoneItem['rect'].width) * 100) / 100;
      hotZoneItem['rect'].height = Math.round( (hotZoneItem['rect'].height) * 100) / 100;

      hotZoneItemArr.push(hotZoneItem);
    }

    console.log('hotZoneItemArr: ', hotZoneItemArr);

    this.save.emit({bgItem, hotZoneItemArr});
  }
}
