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) {// 鼠标在第四象限
    //第一象限
    console.log("第一象限");
    angle = -angle;
  } else if(mx < px && my > py) {
    //第二象限
    console.log("第二象限");
  } else if(mx < px && my < py) {
    //第三象限
    console.log("第三象限");
    angle = 180 - angle;
  } else if(mx > px && my < py) {
    //第四象限
    console.log("第四象限");
    angle = angle - 180;
  }
  if (mx == px) {
    //在y轴上
    console.log("在y轴上");
    angle = 0;
  } else if (my == py) {
    //在x轴上
    console.log("在x轴上");
    angle = 90;

  }

  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 getSpriteFrimeByUrl(url, cb) {
  cc.loader.load({url}, (err, img) => {
    const spriteFrame = new cc.SpriteFrame(img)
    if (cb) {
      cb(spriteFrame);
    }
  })
}

export function getSprNode(resName) {
  // console.log('getSprNode name: ', 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, 0.8);
    if (cb) {
      cc.audioEngine.setFinishCallback(audioId, () => {
        cb();
      });
    }

    return audioId;
	}
}


export function playAudioByUrl(audio_url, cb=null) {
	if (audio_url) {
		cc.assetManager.loadRemote(audio_url, (err, audioClip) => {
      playAudio(audioClip, cb);
		});
	}
}




export async function asyncDelay(time) {
  return new Promise((resolve, reject) => {
    try {
      setTimeout(() => {
        resolve();
      }, time * 1000);
    } catch (e) {
      reject(e);
    }
  })
}

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();
        })
        .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();
        })
        .start();
    } catch (e) {
      reject(e);
    }
  });
}

export function showTrebleFirework(baseNode, rabbonList) {
  const middle = new FireworkSettings(baseNode, rabbonList);
  middle.pos = cc.v2(0, -600);
  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, -600);
  left.side = cc.v2(200, 1000);

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

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


export function delayCall(time, cb) {
  return cc.tween({})
    .delay(time) 
    .call(() => {
      if (cb) {
        cb();
      }
    })
    .start();
}

export function removeFromArr(arr, item) {
  const index = arr.indexOf(item);
  if (index != -1) {
    arr.splice(index, 1);
    return true;
  }
  return false;
}


export function showBtnAnima(btn, cb=null) {

  const baseS = btn.scale;
  cc.tween(btn)
    .to(0.05, {scale: 0.9 * baseS})
    .to(0.05, {scale: 1 * baseS})
    .call(() => {
      if (cb) {
        cb();
      }
    })
    .start();
}

export function jellyShake(node) {
  const baseS = node.scale;
  const time = 1;
  cc.tween(node)
    .to(time / 5 / 2, {scaleX: baseS * 0.8, scaleY: baseS * 1.2}, {easing: "sineInOut"})
    .to(time / 5, {scaleX: baseS * 1.1, scaleY: baseS * 0.9}, {easing: "sineInOut"})
    .to(time / 5, {scaleX: baseS * 0.95, scaleY: baseS * 1.15}, {easing: "sineInOut"})
    .to(time / 5, {scaleX: baseS * 1.02, scaleY: baseS * 0.98}, {easing: "sineInOut"})
    .to(time / 5, {scaleX: baseS * 1, scaleY: baseS * 1}, {easing: "sineInOut"})
    .start();
}


export function onHomeworkFinish(data) {
  const middleLayer = cc.find('middleLayer');
  if (middleLayer) {
    const middleLayerComponent = middleLayer.getComponent('middleLayer');
    middleLayerComponent.onHomeworkFinish(() => { }, data);

    return;
  }
}


export function roundNum(num, smallNum) {

  return Math.round(num * smallNum) / smallNum
}

