import {
  MySprite,
  Label,
  removeItemFromArr,
  hideItem,
  showItem,
  moveItem,
  tweenChange,
} from '../Unit';

import TWEEN from '@tweenjs/tween.js';

export class Game {
  _parent = null;
  _z = 0;
  children: any = [this];

  constructor(parent) {
    this._parent = parent;
  }

  initData(data) {

  }

  _initView() {
    this._checkFonts(() => {
      this.initView();
    });
  }

  _fontNameList = [];
  _checkFonts(cb) {
    let unloaded = false;
    document['fonts'].forEach((font) => {
      if (font.status === 'unloaded') {
        unloaded = true;
      }
    });

    if (unloaded) {
      setTimeout(() => this._checkFonts(cb), 100);
      return;
    }
    cb();
  }

  initView() {

  }

  _currentPlayingAudioName;
  playAudio(key, now = true, callback = null) {

    if (this._currentPlayingAudioName != '') {
      const audio = this._parent.audioObj[this._currentPlayingAudioName];
      if (audio) {
        if (now) {
          if (!audio.paused) {
            audio.pause();
            // audio.currentTime = 0;
          }
        }
      }
    }

    this._currentPlayingAudioName = key;
    this._parent.playAudio(key, now, () => {
      this._currentPlayingAudioName = '';
      if (callback) {
        callback();
      }
    });
  }

  getAudioObj(key) {
    return this._parent.audioObj[key];
  }

  _editMode = false;
  setEditMode(flg) {
    this._editMode = flg;
  }
  isEditMode() {
    return this._editMode;
  }
  _save;
  setSaveFunc(save) {
    this._save = save;
  }

  addChild(node, z = 1) {
    this._parent.renderArr.push(node);

    if (this.children.indexOf(node) === -1) {
      this.children.push(node);
      node._z = z;
    }

    this.children.sort((a, b) => {
      return a._z - b._z;
    });
  }

  removeChildren() {
    for (let i = 0; i < this.children.length; i++) {
      if (this.children[i]) {
        if (this.children[i] !== this) {
          let child = this.children.splice(i, 1);
          removeItemFromArr(this._parent.renderArr, child);
          i--;
        }
      }
    }
  }
  removeChild(child) {
    const index = this.children.indexOf(child);
    if (index !== -1) {
      this.children.splice(index, 1);
    }
    removeItemFromArr(this._parent.renderArr, child);
  }

  _checkHitPosition(node, pos) {
    let rightNode = null;
    if (node.visible && node.alpha > 0 && node._touchEnabled && node._checkHitPosition(pos)) {
      rightNode = node;
    }
    if (node.children.length > 1) {
      for (var i = 1; i < node.children.length; ++i) {
        if (node.children[i] != node) {
          let result = this._checkHitPosition(node.children[i], pos);
          if (result != null) {
            rightNode = result;
          }
        }
      }
    }
    return rightNode;
  }

  _currentTouchSprite = null;
  _onTouchBegan(pos) {
    let result = this._checkHitPosition(this, pos);
    if (result == null) {
      return;
    }
    if (result._onTouchBeganListener &&
      typeof (result._onTouchBeganListener) == 'function') {
      result._onTouchBeganListener(pos);
    }
    this._currentTouchSprite = result;
  }
  _onTouchMove(pos) {
    if (this._currentTouchSprite == null) {
      return;
    }
    if (this._currentTouchSprite._onTouchMoveListener &&
      typeof (this._currentTouchSprite._onTouchMoveListener) == 'function') {
      this._currentTouchSprite._onTouchMoveListener(pos);
    }
  }
  _onTouchEnd(pos) {
    if (this._currentTouchSprite == null) {
      return;
    }
    if (this._currentTouchSprite._checkHitPosition(pos)) {
      if (this._currentTouchSprite._onTouchEndListener &&
        typeof (this._currentTouchSprite._onTouchEndListener) == 'function') {
        this._currentTouchSprite._onTouchEndListener(pos);
      }
      this._currentTouchSprite = null;
    } else {
      if (this._currentTouchSprite._onTouchCancelListener &&
        typeof (this._currentTouchSprite._onTouchCancelListener) == 'function') {
        this._currentTouchSprite._onTouchCancelListener(pos);
      }
      this._currentTouchSprite = null;
    }
  }

  getChildByName(name) {
    for (var i = 1; i < this.children.length; ++i) {
      let node = this.children[i];
      if (node.getName() == name) {
        return node;
      }
    }
    return null;
  }
  seekChildByName(name) {
    let result = this.getChildByName(name);
    if (result == null) {
      for (var i = 1; i < this.children.length; ++i) {
        let node = this.children[i];
        if (typeof (node.seekChildByName) == 'function') {
          result = node.seekChildByName(name);
          if (result != null) {
            return result;
          }
        }
      }
    }
    return result;
  }

  getScreenSize() {
    return {
      width: this._parent.canvasWidth,
      height: this._parent.canvasHeight
    };
  }

  getDefaultScreenSize() {
    return {
      width: this._parent.canvasBaseW,
      height: this._parent.canvasBaseH
    };
  }

  getFullScaleXY() {
    let screenSize = this.getScreenSize();
    let defaultSize = this.getDefaultScreenSize();

    return Math.max(screenSize.height / defaultSize.height, screenSize.width / defaultSize.width);
  }

  _showMode = false;
  showModeOn() {
    this._showMode = true;
  }
  showModeOff() {
    this._showMode = false;
  }
  isShowMode() {
    return this._showMode;
  }
}

// 节点名
class Nameable {
  _parent = null;
  constructor(parent) {
    this._parent = parent;
  }

  _name = 'name';
  setName(name) {
    this._name = name;
  }
  getName() {
    return this._name;
  }
  getChildByName(name) {
    for (var i = 1; i < this._parent.children.length; ++i) {
      let node = this._parent.children[i];
      if (node.getName() == name) {
        return node;
      }
    }
    return null;
  }
  seekChildByName(name) {
    let result = this.getChildByName(name);
    if (result == null) {
      for (var i = 1; i < this._parent.children.length; ++i) {
        let node = this._parent.children[i];
        if (typeof (node.seekChildByName) == 'function') {
          result = node.seekChildByName(name);
          if (result != null) {
            return result;
          }
        }
      }
    }
    return result;
  }
}

class UserData {
  // 用户自定义数据
  userData = {};
  get(key) {
    return this.userData[key];
  }
  set(key, value) {
    this.userData[key] = value;
  }
}

export class MyLabel extends Label {
  _nameable = new Nameable(this);
  setName(name) {
    this._nameable.setName(name);
  }
  getName() {
    return this._nameable.getName();
  }
  getChildByName(name) {
    return this._nameable.getChildByName(name);
  }
  seekChildByName(name) {
    return this._nameable.seekChildByName(name);
  }

  // 位置
  setPosition(x: any = 0, y = undefined) {
    if (y !== undefined) {
      this.x = x;
      this.y = y;
    } else {
      this.x = x.x;
      this.y = x.y;
    }
  }
  setPositionX(x = 0) {
    this.x = x;
  }
  setPositionY(y = 0) {
    this.y = y;
  }

  _userData = new UserData();
  get(key) {
    return this._userData.get(key);
  }
  set(key, value) {
    this._userData.set(key, value);
  }

  _touchEnabled = false;
  // _swallowTouches = false;		// TODO:多重触摸以后用到了再说

  _onTouchBeganListener = null;
  _onTouchMoveListener = null;
  _onTouchEndListener = null;
  _onTouchCancelListener = null;

  addTouchBeganListener(func) {
    this._touchEnabled = true;
    this._onTouchBeganListener = func;
  }
  addTouchMoveListener(func) {
    this._touchEnabled = true;
    this._onTouchMoveListener = func;
  }
  addTouchEndListener(func) {
    this._touchEnabled = true;
    this._onTouchEndListener = func;
  }
  addTouchCancelListener(func) {
    this._touchEnabled = true;
    this._onTouchCancelListener = func;
  }

  _checkHitPosition(pos) {
    const rect = this.getBoundingBox();

    if (this._checkPointInRect(pos.x, pos.y, 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;
  }

  drawText() {
    if (!this.text) {
      return;
    }

    this.ctx.font = `${this.fontSize}px ${this.fontName}`;
    this.ctx.textAlign = this.textAlign;
    this.ctx.textBaseline = 'middle';
    this.ctx.fontWeight = this.fontWeight;

    let x = -(this.anchorX) * this._width;
    let y = 0;

    if (this._outlineFlag) {
      this.ctx.lineWidth = this._outLineWidth;
      this.ctx.strokeStyle = this._outLineColor;
      this.ctx.strokeText(this.text, x, y);
    }

    this.ctx.fillStyle = this.fontColor;

    if (this.outline > 0) {
      this.ctx.lineWidth = this.outline;
      this.ctx.strokeStyle = this.outlineColor;
      this.ctx.strokeText(this.text, x, y);
    }

    this.ctx.fillText(this.text, x, y);
    // console.log('汪汪汪: ' + this.scaleX * this.anchorX);
    // console.log('汪汪汪: ' + this._width);
  }
}

export class TouchSprite extends MySprite {
  _nameable = new Nameable(this);
  setName(name) {
    this._nameable.setName(name);
  }
  getName() {
    return this._nameable.getName();
  }
  getChildByName(name) {
    return this._nameable.getChildByName(name);
  }
  seekChildByName(name) {
    return this._nameable.seekChildByName(name);
  }

  _touchEnabled = false;
  // _swallowTouches = false;		// TODO:多重触摸以后用到了再说

  _onTouchBeganListener = null;
  _onTouchMoveListener = null;
  _onTouchEndListener = null;
  _onTouchCancelListener = null;

  addTouchBeganListener(func) {
    this._touchEnabled = true;
    this._onTouchBeganListener = func;
  }
  addTouchMoveListener(func) {
    this._touchEnabled = true;
    this._onTouchMoveListener = func;
  }
  addTouchEndListener(func) {
    this._touchEnabled = true;
    this._onTouchEndListener = func;
  }
  addTouchCancelListener(func) {
    this._touchEnabled = true;
    this._onTouchCancelListener = func;
  }

  _checkHitPosition(pos) {
    const rect = this.getBoundingBox();

    if (this._checkPointInRect(pos.x, pos.y, 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;
  }

  // 位置
  setPosition(x: any = 0, y = undefined) {
    if (y !== undefined) {
      this.x = x;
      this.y = y;
    } else {
      this.x = x.x;
      this.y = x.y;
    }
  }
  setPositionX(x = 0) {
    this.x = x;
  }
  setPositionY(y = 0) {
    this.y = y;
  }

  // 用户自定义数据
  _userData = new UserData();
  get(key) {
    return this._userData.get(key);
  }
  set(key, value) {
    this._userData.set(key, value);
  }
}

export function blinkItem(item: TouchSprite, time = 0.7) {
  let interval = item.get('_blinkInterval');
  if (interval) {
    clearInterval(interval);
  }
  interval = setInterval(() => {
    showItem(item, time, () => {
      hideItem(item, time);
    });
  }, time * 2 * 1000);
  item.set('_blinkInterval', interval);
}

export function stopBlinkItem(item: TouchSprite) {
  let interval = item.get('_blinkInterval');
  if (interval) {
    clearInterval(interval);
  }
  item.set('_blinkInterval', null);
  item.alpha = 0;
}

export function RandomInt(a, b = 0) {
  let max = Math.max(a, b);
  let min = Math.min(a, b);
  return Math.floor(Math.random() * (max - min) + min);
}

export function Between(a, b, c) {
  let max = Math.max(a, b, c);
  let min = Math.min(a, b, c);
  return [a, b, c].find((number) => number != max && number != min);
}

export function shake(item, time = 0.5, rate = 1) {
  let shakeSelf = function (item, time, callback, rate) {
    const offX = 15 * item.scaleX * rate;
    const offY = 15 * item.scaleX * rate;
    const baseX = item.x;
    const baseY = item.y;
    const easing = TWEEN.Easing.Sinusoidal.InOut;

    const move2 = () => {
      moveItem(item, baseX, baseY, time * 9 / 16, () => {
        if (callback) {
          callback();
        }
      }, easing);
    };

    const move1 = () => {
      moveItem(item, baseX + offX, baseY + offY, time * 7 / 16, () => {
        move2();
      }, easing);
    };

    move1();
  }

  shakeSelf(item, time, shake.bind(this, item, time, rate), rate);
}

export async function asyncDelayTime(time) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(123);
    }, time * 1000);
  })
}

export async function asyncTweenChange(node, obj, time, easing = null) {
  return new Promise((resolve, reject) => {
    tweenChange(node, obj, time, () => {
      resolve(0);
    }, easing);
  });
}