export function getPosByAngle(angle, len) {

  const radian = angle * Math.PI / 180;
  const x = Math.sin(radian) * len;
  const y = Math.cos(radian) * len;

  return { x, y };

}

export function getAngleByPos(px, py, mx, my) {

  const x = Math.abs(px - mx);
  const y = Math.abs(py - my);

  const z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
  const cos = y / z;
  const radina = Math.acos(cos); // 用反三角函数求弧度
  let angle = Math.floor(180 / (Math.PI / radina) * 100) / 100; // 将弧度转换成角度

  if (mx > px && my > py) {// 鼠标在第四象限
    angle = 180 - angle;
  }
  if (mx === px && my > py) {// 鼠标在y轴负方向上
    angle = 180;
  }
  if (mx > px && my === py) {// 鼠标在x轴正方向上
    angle = 90;
  }
  if (mx < px && my > py) {// 鼠标在第三象限
    angle = 180 + angle;
  }
  if (mx < px && my === py) {// 鼠标在x轴负方向
    angle = 270;
  }
  if (mx < px && my < py) {// 鼠标在第二象限
    angle = 360 - angle;
  }

  // console.log('angle: ', angle);
  return angle;

}

export function exchangeNodePos(baseNode, targetNode) {
  return baseNode.convertToNodeSpaceAR(targetNode._parent.convertToWorldSpaceAR(cc.v2(targetNode.x, targetNode.y)));
}

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 randomSortByArr(arr) {
  const newArr = [];
  const tmpArr = arr.concat();
  while (tmpArr.length > 0) {
    const randomIndex = Math.floor(tmpArr.length * Math.random());
    newArr.push(tmpArr[randomIndex]);
    tmpArr.splice(randomIndex, 1);
  }
  return newArr;
}

export function setSprNodeMaxLen(sprNode, maxW, maxH) {
  const sx = maxW / sprNode.width;
  const sy = maxH / sprNode.height;
  const s = Math.min(sx, sy);
  sprNode.scale = Math.round(s * 1000) / 1000;
}

export function localPosTolocalPos(baseNode, targetNode) {
	const worldPos = targetNode.parent.convertToWorldSpaceAR(cc.v2(targetNode.x, targetNode.y));
	const localPos = baseNode.parent.convertToNodeSpaceAR(cc.v2(worldPos.x, worldPos.y));
	return localPos;
}

export function worldPosToLocalPos(worldPos, baseNode) {
	const localPos = baseNode.parent.convertToNodeSpaceAR(cc.v2(worldPos.x, worldPos.y));
	return localPos;
}

export function getScaleRateBy2Node(baseNode, targetNode, maxFlag = true) {
	const worldRect1 = targetNode.getBoundingBoxToWorld();
	const worldRect2 = baseNode.getBoundingBoxToWorld();

	const sx = worldRect1.width / worldRect2.width;
	const sy = worldRect1.height / worldRect2.height;
	if (maxFlag) {
		return Math.max(sx, sy);
	} else {
		return Math.min(sx, sy);
	}
}

export function getDistance (start, end){
    var pos = cc.v2(start.x - end.x, start.y - end.y);
    var dis = Math.sqrt(pos.x*pos.x + pos.y*pos.y);
    return dis;
}

export function playAudioByUrl(audio_url, cb=null) {
	if (audio_url) {
		cc.assetManager.loadRemote(audio_url, (err, audioClip) => {
      const audioId = cc.audioEngine.play(audioClip, false, 0.8);
      if (cb) {
        cc.audioEngine.setFinishCallback(audioId, () => {
          cb();
        });
      }
		});
	}
}


export function btnClickAnima(btn, time=0.15, rate=1.05) {
  btn.tmpScale = btn.scale;
  btn.on(cc.Node.EventType.TOUCH_START, () => {
    cc.tween(btn)
      .to(time / 2, {scale: btn.scale * rate})
      .start()
  })
  btn.on(cc.Node.EventType.TOUCH_CANCEL, () => {
    cc.tween(btn)
      .to(time / 2, {scale: btn.tmpScale})
      .start()
  })
  btn.on(cc.Node.EventType.TOUCH_END, () => {
    cc.tween(btn)
      .to(time / 2, {scale: btn.tmpScale})
      .start()
  })
}


export function getSpriteFrimeByUrl(url, cb) {
  cc.loader.load({ url }, (err, img) => {
    const spriteFrame = new cc.SpriteFrame(img)
    if (cb) {
      cb(spriteFrame);
    }
  })
}

export function getSprNode(resName) {
  const sf = cc.find('Canvas/res/img/' + resName).getComponent(cc.Sprite).spriteFrame;
  const node = new cc.Node();
  node.addComponent(cc.Sprite).spriteFrame = sf;
  return node;
}

export function getSprNodeByUrl(url, cb) {
  const node = new cc.Node();
  const spr = node.addComponent(cc.Sprite);
  getSpriteFrimeByUrl(url, (sf) => {
    spr.spriteFrame = sf;
    if (cb) {
      cb(spr);
    }
  })
}



export function playAudio(audioClip, cb = null) {
  if (audioClip) {
    const audioId = cc.audioEngine.playEffect(audioClip, false);
    if (cb) {
      cc.audioEngine.setFinishCallback(audioId, () => {
        cb();
      });
    }
  }
}

export async function asyncDelay(time) {
  return new Promise((resolve, reject) => {
    try {
      cc.tween(cc.find('Canvas'))
        .delay(time)
        .call(()=>{
          resolve(null);
        })
        .start();
    } catch (e) {
      reject(e);
    }
  })
}

export async function asyncLoadDragonBoneAnime(node, { skeJsonData: { url: skeJsonDataUrl }, texJsonData: { url: texJsonDataUrl }, texPngData: { url: texPngDataUrl } }) {

    if (!texPngDataUrl || !texJsonDataUrl || !texPngDataUrl
        || texPngDataUrl == '' || texJsonDataUrl == '' || texPngDataUrl == '') {
        return;
    }

    return new Promise((resolve, reject) => {
        if (node.animaNode) {
            node.animaNode.removeFromParent();
        }
        const animaNode = new cc.Node();
        animaNode.name = 'animaNode';
        animaNode.parent = node;
        animaNode.active = true;
        node.animaNode = animaNode;

        const dragonDisplay = animaNode.addComponent(dragonBones.ArmatureDisplay);

        const loadTexture = new Promise((resolve, reject) => {
            cc.assetManager.loadRemote(texPngDataUrl, (error, texture) => {
                if (error) {
                    reject(error);
                }
                resolve(texture);
            });
        });

        const loadTexJsonData = new Promise((resolve, reject) => {
            cc.assetManager.loadAny({ url: texJsonDataUrl }, (error, atlasJson) => {
                if (error) {
                    reject(error);
                }
                resolve(atlasJson);
            });
        });

        const loadSkeJsonData = new Promise((resolve, reject) => {
            cc.assetManager.loadAny({ url: skeJsonDataUrl }, (error, dragonBonesJson) => {
                if (error) {
                    reject(error);
                }
                resolve(dragonBonesJson);
            });
        });

        Promise.all([loadTexture, loadTexJsonData, loadSkeJsonData]).then(([texture, atlasJson, dragonBonesJson]) => {
            const atlas = new dragonBones.DragonBonesAtlasAsset();
            atlas.atlasJson = JSON.stringify(atlasJson);
            atlas.texture = texture;

            const asset = new dragonBones.DragonBonesAsset();
            asset.dragonBonesJson = JSON.stringify(dragonBonesJson);

            dragonDisplay.dragonAtlasAsset = atlas;
            dragonDisplay.dragonAsset = asset;

            let armatureNames = dragonBonesJson.armature.map(data => data.name);

            if (armatureNames.length > 0) {
                dragonDisplay.armatureName = armatureNames[0];
            }
            resolve(animaNode);
        });
    });
}

export class FireworkSettings {
  baseNode; // 父节点
  nodeList; // 火花节点的array
  pos; // 发射点
  side; // 发射方向
  range; // 扩散范围
  number; // 发射数量
  scalseRange; // 缩放范围
  constructor(baseNode, nodeList,
    pos = cc.v2(0, 0),
    side = cc.v2(0, 100),
    range = 50,
    number = 100,
    scalseRange = 0
  ) {
    this.baseNode = baseNode;
    this.nodeList = nodeList;
    this.pos = pos;
    this.side = side;
    this.range = range;
    this.number = number;
    this.scalseRange = scalseRange;
  }

  static copy(firework) {
    return new FireworkSettings(
      firework.baseNode,
      firework.nodeList,
      firework.pos,
      firework.side,
      firework.range,
      firework.number,
    );
  }
}

export async function showFireworks(fireworkSettings) {
  const { baseNode, nodeList, pos, side, range, number, scalseRange } = fireworkSettings;
  new Array(number).fill(' ').forEach(async (_, i) => {

    let rabbonNode = new cc.Node();
    rabbonNode.parent = baseNode;
    rabbonNode.x = pos.x;
    rabbonNode.y = pos.y;
    rabbonNode.angle = 60 * Math.random() - 30;

    let node = cc.instantiate(nodeList[RandomInt(nodeList.length)]);
    node.parent = rabbonNode;
    node.active = true;
    node.x = 0;
    node.y = 0;
    node.angle = 0;
    node.scale = (Math.random() - 0.5) * scalseRange + 1;

    const rate = Math.random();
    const angle = Math.PI * (Math.random() * 2 - 1);

    await asyncTweenBy(rabbonNode, 0.3, {
      x: side.x * rate + Math.cos(angle) * range * rate,
      y: side.y * rate + Math.sin(angle) * range * rate
    }, {
      easing: 'quadIn'
    });

    cc.tween(rabbonNode)
      .by(8, { y: -2000 })
      .start();

    cc.tween(rabbonNode)
      .to(5, { scale: (Math.random() - 0.5) * scalseRange + 1 })
      .start();

    rabbonFall(rabbonNode);

    await asyncDelay(Math.random());
    cc.tween(node)
      .by(0.15, { x: -10, angle: -10 })
      .by(0.3, { x: 20, angle: 20 })
      .by(0.15, { x: -10, angle: -10 })
      .union()
      .repeatForever()
      .start();

    cc.tween(rabbonNode)
      .delay(5)
      .to(0.3, { opacity: 0 })
      .call(() => {
        node.stopAllActions();
        node.active = false;
        node.parent = null;
        node = null;
      })
      .start();
  });
}

async function rabbonFall(node) {
  const time = 1 + Math.random();
  const offsetX = RandomInt(-200, 200) * time;
  await asyncTweenBy(node, time, { x: offsetX, angle: offsetX * 60 / 200 });
  rabbonFall(node);
}


export async function asyncTweenTo(node, duration, obj, ease = undefined) {
  return new Promise((resolve, reject) => {
    try {
      cc.tween(node)
        .to(duration, obj, ease)
        .call(() => {
          resolve(null);
        })
        .start();
    } catch (e) {
      reject(e);
    }
  });
}

export async function asyncTweenBy(node, duration, obj, ease = undefined) {
  return new Promise((resolve, reject) => {
    try {
      cc.tween(node)
        .by(duration, obj, ease)
        .call(() => {
          resolve(null);
        })
        .start();
    } catch (e) {
      reject(e);
    }
  });
}

export function showTrebleFirework(baseNode, rabbonList) {
  const middle = new FireworkSettings(baseNode, rabbonList);
  middle.pos = cc.v2(0, -400);
  middle.side = cc.v2(0, 1000);
  middle.range = 200;
  middle.number = 100;
  middle.scalseRange = 0.4;

  const left = FireworkSettings.copy(middle);
  left.pos = cc.v2(-600, -400);
  left.side = cc.v2(200, 1000);

  const right = FireworkSettings.copy(middle);
  right.pos = cc.v2(600, -400);
  right.side = cc.v2(-200, 1000);

  showFireworks(middle);
  showFireworks(left);
  showFireworks(right);
}

export function httpHeadCall(requsetUrl: string, callback) {
  let xhr = new XMLHttpRequest();
  console.log("Status: Send Post Request to " + requsetUrl);
  try {
    xhr.onreadystatechange = () => {
      try {
        console.log('xhr.readyState: ', xhr.readyState);
        if (xhr.readyState == 4) {
          if ((xhr.status >= 200 && xhr.status < 400)) {
            callback(true);
          } else {
            callback(false);
          }
        }

      } catch (e) {
        console.log(e)
      }
    };
    xhr.open("HEAD", requsetUrl, true);
    xhr.send();
    xhr.timeout = 15000;
    xhr.onerror = (e) => {
      callback(false);
    };
    xhr.ontimeout = (e) => {
      callback(false);
    };
  } catch (e) {
    console.log("Send Get Request error: ", e);
  }
}

export function onHomeworkFinish(data = "", callback = ()=>{}) {
  const middleLayer = cc.find('middleLayer');
  if (middleLayer) {
    const middleLayerComponent = middleLayer.getComponent('middleLayer');
    middleLayerComponent.onHomeworkFinish(callback, data);
  } else {
    console.log('onHomeworkFinish', JSON.stringify(data));
  }
}

export function callMiddleLayerFunction(apiName: string, data: any, callback: Function) {
  const middleLayer = cc.find('middleLayer');
  if (middleLayer) {
    const middleLayerComponent = middleLayer.getComponent('middleLayer');
    middleLayerComponent.callMiddleLayerFunction(apiName, data, callback);
  } else {
    console.log('callMiddleLayerFunction: ' + apiName);
  }
}

export function showTips(tips) {
  const middleLayer = cc.find('middleLayer');
  if (middleLayer) {
      middleLayer.getComponent('middleLayer').showTips(tips);    
  } else {
      console.log(tips);
  }
}



