<script setup>
/**
 * @file  Genie组件说明
 *   Genie：收缩或者放出效果的组件
 *       props说明:
 *           @prop {Number} width     (必填)    组件的基础宽度
 *           @prop {Number} height    (必填)    组件的基础高度
 *           @prop {Number} top       (非必填)   组件的基础top
 *           @prop {Number} left      (非必填)   组件的基础left
 *           @prop {Number} time      (非必填)   组件的动画时长
 *           @prop {Object} position  (必填)    组件收缩点的坐标
 *           @prop {String} direction (必填)    组件动画方向
 *           @prop {Function} animationEnd (非必填)    组件做完一次动画后的回调
 *            @prop {Boolean}  initShow   (必填)    组件初始状态
 *       methods:
 *           @method switcher 暴露出去的方法 交替组件内部显示情况
 *
 */

import genieLeft from "./genieLeft.glsl?raw";
import genieRight from "./genieRight.glsl?raw";
import genieBottom from "./genieBottom.glsl?raw";
import genieTop from "./genieTop.glsl?raw";
import {
  shallowRef,
  computed,
  onMounted,
  onUnmounted,
  onBeforeUnmount,
  watchEffect,
} from "vue";
import {
  JsvFragShaderView,
  getKeyFramesGroup,
  JsvTextureStoreApi,
} from "jsview";
const props = defineProps({
  width: { type: Number, require: true },
  height: { type: Number, require: true },
  left: { type: Number, default: 0 },
  top: { type: Number, default: 0 },
  time: { type: Number, default: 2 },
  position: { type: Object, require: true },
  size: { type: Number, default: 1 },
  direction: { type: String, require: true },
  onAnimEnd: { type: Function, default: () => {} },
  initShow: { type: Boolean, require: true },
});

let rShow = shallowRef(false);
let rFlag = shallowRef(true);
//是否第一次动画
let initAni = true;
//动画
const cStyleShell = getKeyFramesGroup();
//动画字符串
let rAniStr = shallowRef("release");
//位移动画中心点方向
let vTransformDirection = "";
//形变比例
let vTransformScale = 1;
//自动播放控制
let autoControl = shallowRef(false);
//shader模型
let vTempMode = "";
let vShaderMode = "";
//替换
let rReplacedShader = shallowRef("");
//动画
let vContract;
let vRelease;
//位移量
let vDistanceX;
let vDistanceY;
//shader动画的参数
let vRange1;
let vRange2;

//在组件外部的八种情况
//左上方
if (props.position.x < 0 && props.position.y < 0) {
  vDistanceX = props.position.x;
  vDistanceY = props.position.y;
  //释放的动画
  vRelease = `@keyframes release {
            0% {
              transform: translate3d(${vDistanceX},${vDistanceY}, 0);
            }
              70%{
              transform: translate3d(${vDistanceX},${vDistanceY}, 0);
              }
              80% {
          transform: translate3d(0, 0, 0);
            }
              100% {
              transform: translate3d(0, 0, 0);
            }
          }`;
  vContract = `@keyframes contract {
            0% {
              transform: translate3d(0, 0, 0);
            }
              30% {
             transform: translate3d(0, 0, 0);
            }
              40%{
               transform: translate3d(${vDistanceX}, ${vDistanceY}, 0);
              }
              100% {
              transform: translate3d(${vDistanceX}, ${vDistanceY}, 0);
            }
          }`;
  if (props.direction == "horizontal") {
    vShaderMode = genieLeft;
    vRange1 = 1 - 1 / props.height;
    vRange2 = 1 - 2 / props.height;
  } else if (props.direction == "vertical") {
    vShaderMode = genieTop;
    vRange1 = 1 / props.width;
    vRange2 = 2 / props.width;
  }
} else if (props.position.x < props.width && props.position.y < 0) {
  //正上方
  vDistanceY = props.position.y;
  //释放的动画
  vRelease = `@keyframes release {
            0% {
              transform: translate3d(0,${vDistanceY}, 0);
            }
              70% {
              transform: translate3d(0,${vDistanceY}, 0);
            }
               80%{
              transform: translate3d(0, 0, 0);
              }
  
              100% {
              transform: translate3d(0, 0, 0);
            }
          }`;
  vContract = `@keyframes contract {
            0% {
              transform: translate3d(0, 0, 0);
            }
              30% {
              transform: translate3d($0, 0, 0);
            }
              40%{
               transform: translate3d($0, ${vDistanceY}, 0);
              }
              100% {
              transform: translate3d(0, ${vDistanceY}, 0);
            }
          }`;

  vShaderMode = genieTop;

  vRange1 = (props.position.x + 1) / props.width;
  vRange2 = props.position.x / props.width;
} else if (props.position.x > props.width && props.position.y < 0) {
  //右上角
  if (props.direction == "horizontal") {
    vDistanceX = props.position.x - props.width;
    vDistanceY = props.position.y;
    vShaderMode = genieRight;
    vRange1 = 1 - 1 / props.height;
    vRange2 = 1 - 2 / props.height;
  } else if (props.direction == "vertical") {
    vDistanceX = props.position.x - props.width;
    vDistanceY = props.position.y;
    vShaderMode = genieTop;
    vRange2 = 1 - 2 / props.width;
    vRange1 = 1 - 1 / props.width;
  }
  //释放的动画
  vRelease = `@keyframes release {
            0% {
              transform: translate3d(${vDistanceX},${vDistanceY}, 0);
            }
              70% {
              transform: translate3d(${vDistanceX},${vDistanceY}, 0);
            }
              80%{
               transform: translate3d(0, 0, 0);
              }
              100% {
              transform: translate3d(0, 0, 0);
            }
          }`;
  vContract = `@keyframes contract {
            0% {
              transform: translate3d(0, 0, 0);
            }
              30% {
               transform: translate3d(0, 0, 0);
            }
              40%{
              transform: translate3d(${vDistanceX}, ${vDistanceY}, 0);
              }
              100% {
              transform: translate3d(${vDistanceX}, ${vDistanceY}, 0);
            }
          }`;
} else if (
  props.position.x < 0 &&
  props.position.y > 0 &&
  props.position.y <= props.height
) {
  //正左边
  vDistanceX = props.position.x;
  //释放的动画
  vRelease = `@keyframes release {
            0% {
              transform: translate3d(${vDistanceX},0, 0);
            }
              70% {
              transform: translate3d(${vDistanceX},0, 0);
            }
              80%{
               transform: translate3d(0, 0, 0);
              }
              100% {
              transform: translate3d(0, 0, 0);
            }
          }`;
  vContract = `@keyframes contract {
            0% {
              transform: translate3d(0, 0, 0);
            }
              30% {
              transform: translate3d(0, 0, 0);
            }
              40%{
              transform: translate3d(${vDistanceX},0, 0);
              }
              100% {
              transform: translate3d(${vDistanceX},0, 0);
            }
          }`;

  vShaderMode = genieLeft;

  vRange2 = 1 - props.position.y / props.height;
  vRange1 = 1 - (props.position.y + 1) / props.height;
} else if (
  props.position.x > props.width &&
  props.position.y > 0 &&
  props.position.y <= props.height
) {
  //正右边
  vDistanceX = props.position.x - props.width;
  vDistanceY = props.position.y;
  vShaderMode = genieRight;
  vRange1 = 1 - props.position.y / props.height;
  vRange2 = 1 - (1 + props.position.y) / props.height;
  //释放的动画
  vRelease = `@keyframes release {
            0% {
              transform: translate3d(${vDistanceX},0, 0);
            }
              70% {
              transform: translate3d(${vDistanceX},0, 0);
            }
              80%{
              transform: translate3d(0, 0, 0);
              }
              100% {
              transform: translate3d(0, 0, 0);
            }
          }`;
  vContract = `@keyframes contract {
            0% {
              transform: translate3d(0, 0, 0);
            }
              30% {
             transform: translate3d(0, 0, 0);
            }
              40%{
               transform: translate3d(${vDistanceX},0, 0);
              }
              100% {
              transform: translate3d(${vDistanceX},0, 0);
            }
          }`;
} else if (props.position.x < 0 && props.position.y > props.height) {
  //左下方
  if (props.direction == "horizontal") {
    vDistanceX = props.position.x;
    vDistanceY = props.position.y - props.height;
    vShaderMode = genieLeft;
    vRange2 = 1 / props.height;
    vRange1 = (1 + 1) / props.height;
  } else if (props.direction == "vertical") {
    vDistanceX = props.position.x;
    vDistanceY = props.position.y - props.height;
    vShaderMode = genieBottom;
    vRange1 = 1 / props.width;
    vRange2 = (1 + 1) / props.width;
  }
  //释放的动画
  vRelease = `@keyframes release {
            0% {
              transform: translate3d(${vDistanceX},${vDistanceY}, 0);
            }
              70% {
             transform: translate3d(${vDistanceX},${vDistanceY}, 0);
            }
              80%{
               transform: translate3d(0, 0, 0);
              }
              100% {
              transform: translate3d(0, 0, 0);
            }
          }`;
  vContract = `@keyframes contract {
            0% {
              transform: translate3d(0, 0, 0);
            }
              30% {
               transform: translate3d(0, 0, 0);
            }
              40%{
              transform: translate3d(${vDistanceX}, ${vDistanceY}, 0);
              }
              100% {
              transform: translate3d(${vDistanceX}, ${vDistanceY}, 0);
            }
          }`;
} else if (
  props.position.x > 0 &&
  props.position.x < props.width &&
  props.position.y > props.height
) {
  //正下方
  vDistanceY = props.position.y - props.height;
  //释放的动画
  vRelease = `@keyframes release {
            0% {
              transform: translate3d(0,${vDistanceY}, 0);
            }
              70% {
               transform: translate3d(0,${vDistanceY}, 0);
            } 
              80%{
              transform: translate3d(0, 0, 0);
              }
              100% {
              transform: translate3d(0, 0, 0);
            }
          }`;
  vContract = `@keyframes contract {
            0% {
              transform: translate3d(0, 0, 0);
            }
              30% {
               transform: translate3d(0, 0, 0);
            }
              40%{
              transform: translate3d($0, ${vDistanceY}, 0);
              }
              100% {
              transform: translate3d(0, ${vDistanceY}, 0);
            }
          }`;

  vShaderMode = genieBottom;

  vRange1 = props.position.x / props.width;
  vRange2 = (props.position.x - 1) / props.width;
} else if (props.position.x > props.width && props.position.y > props.height) {
  //右下方
  if (props.direction == "horizontal") {
    vDistanceX = props.position.x - props.width;
    vDistanceY = props.position.y - props.height;
    vShaderMode = genieRight;
    vRange2 = 1 / props.height;
    vRange1 = (1 + 1) / props.height;
  } else if (props.direction == "vertical") {
    vDistanceX = props.position.x - props.width;
    vDistanceY = props.position.y - props.height;
    vShaderMode = genieBottom;
    vRange2 = 1 - 2 / props.width;
    vRange1 = 1 - 1 / props.width;
  }
  //释放的动画
  vRelease = `@keyframes release {
            0% {
              transform: translate3d(${vDistanceX},${vDistanceY}, 0);
            }
              70% {
              transform: translate3d(${vDistanceX},${vDistanceY}, 0);
            }
              80%{
              transform: translate3d(0, 0, 0);
              }
              100% {
              transform: translate3d(0, 0, 0);
            }
          }`;
  vContract = `@keyframes contract {
            0% {
              transform: translate3d(0, 0, 0);
            }
              30% {
              transform: translate3d(0, 0, 0);
            }
              40%{
               transform: translate3d(${vDistanceX}, ${vDistanceY}, 0);
              }
              100% {
              transform: translate3d(${vDistanceX}, ${vDistanceY}, 0);
            }
          }`;
} else {
  //在组件内
  //根据传入进来的方向和中心点位置确定缩放动画
  if (props.direction == "vertical") {
    if (props.position.y < props.height / 2) {
      vTransformDirection = "bottom center";
      vShaderMode = genieTop;
      vTransformScale = 1 - props.position.y / props.height;
    } else {
      vTransformDirection = "top center";
      vShaderMode = genieBottom;
      vTransformScale = props.position.y / props.height;
    }
    vRange1 = props.position.x / props.width;
    vRange2 = (props.position.x - 1) / props.width;
  } else if (props.direction == "horizontal") {
    //解析坐标位置是否要进行移动动画
    if (props.position.x < props.width / 2) {
      vTransformDirection = "center right";
      vShaderMode = genieLeft;
      vTransformScale = 1 - props.position.x / props.width;
    } else {
      vTransformDirection = "center left";
      vShaderMode = genieRight;
      vTransformScale = props.position.x / props.width;
    }
    vRange1 = 1 - props.position.y / props.height;
    vRange2 = 1 - (props.position.y + 1) / props.height;
  }

  if (props.direction == "horizontal") {
    //   //收的动画
    vContract = `@keyframes contract {
              0% {
                transform: scale3d(1, 1, 1);
                transform-origin:${vTransformDirection};
              }
                30% {
                transform: scale3d(${vTransformScale}, 1, 1);
                transform-origin:${vTransformDirection};
              }
                100% {
                transform: scale3d(${vTransformScale}, 1, 1);
                transform-origin:${vTransformDirection};
              }
            }`;
    //   //释放的动画
    vRelease = `@keyframes release {
              0% {
                transform: scale3d(${vTransformScale}, 1, 1);
                transform-origin:${vTransformDirection};
              }
                70% {
                transform: scale3d(${vTransformScale}, 1, 1);
                transform-origin:${vTransformDirection};
              }
                100% {
                transform: scale3d(1, 1, 1);
                transform-origin:${vTransformDirection};
              }
            }`;
  } else if (props.direction == "vertical") {
    //收的动画
    vContract = `@keyframes contract {
              0% {
                transform: scale3d(1, 1, 1);
                transform-origin:${vTransformDirection};
              }
                30% {
                transform: scale3d(1,${vTransformScale}, 1);
                transform-origin:${vTransformDirection};
              }
                100% {
                transform: scale3d(1, ${vTransformScale}, 1);
                transform-origin:${vTransformDirection};
              }
            }`;
    //释放的动画
    vRelease = `@keyframes release {
              0% {
                transform: scale3d(1,${vTransformScale}, 1);
                transform-origin:${vTransformDirection};
              }
                70% {
                transform: scale3d(1,${vTransformScale}, 1);
                transform-origin:${vTransformDirection};
              }
                100% {
                transform: scale3d(1, 1, 1);
                transform-origin:${vTransformDirection};
              }
            }`;
  }
}
//根据初始状态展示
if (props.initShow) {
  rShow.value = true;
  rFlag.value = false;
  rAniStr.value = "contract";
  vTempMode = vShaderMode.replace(/\$\{myTime\}/g, "iTime / iDuration");
} else {
  rShow.value = false;
  rFlag.value = false;
  rAniStr.value = "release";
  vTempMode = vShaderMode.replace(
    /\$\{myTime\}/g,
    "(iDuration - iTime) / iDuration"
  );
}
rReplacedShader = vTempMode
  .replace(/\$\{RANGE_1\}/g, vRange1)
  .replace(/\$\{RANGE_2\}/g, vRange2);

//结束动画函数
const EndAni = () => {
  if (rAniStr.value == "release") {
    rFlag.value = false;
    rShow.value = true;
  } else {
    rFlag.value = false;
    rShow.value = false;
  }
};
//配置
const cShaderSettings = {
  name: "genieLeft",
  shader: rReplacedShader,
  uniforms: [],
  textures: [
    {
      name: "iChannel0",
      resource: null,
    },
  ],
  duration: props.time * 1000,
  onEnd: EndAni,
};

cStyleShell.insertRule(vContract);
cStyleShell.insertRule(vRelease);
let rWidgetRef = shallowRef(null);
const rShaderInfo = computed(() => {
  return cShaderSettings;
});

let vNextTickStartAnimTimer = -1;

function doAnim() {
  if (initAni) {
    rFlag.value = true;
    if (vNextTickStartAnimTimer != -1) {
      clearTimeout(vNextTickStartAnimTimer);
    }
    vNextTickStartAnimTimer = setTimeout(() => {
      rShow.value = false;
      rWidgetRef.value?.startAnim();
      vNextTickStartAnimTimer = -1;
    }, 0);
    initAni = false;
  } else {
    rFlag.value = true;
    if (rAniStr.value == "release") {
      rAniStr.value = "contract";
      rReplacedShader = rReplacedShader.replace(
        "(iDuration - iTime) / iDuration",
        "iTime / iDuration"
      );
      cShaderSettings.shader = rReplacedShader;
    } else {
      rAniStr.value = "release";
      rReplacedShader = rReplacedShader.replace(
        "iTime / iDuration",
        "(iDuration - iTime) / iDuration"
      );
      cShaderSettings.shader = rReplacedShader;
    }
    if (vNextTickStartAnimTimer != -1) {
      clearTimeout(vNextTickStartAnimTimer);
    }
    vNextTickStartAnimTimer = setTimeout(() => {
      rShow.value = false;
      rWidgetRef.value?.startAnim();
    }, 0);
  }
}

const switcher = () => {
  JsvTextureStoreApi.capture2Texture(
    slotRootRef.value,
    (textureName, autoRecycle, w, h) => {
      cShaderSettings.textures[0].resource = `jsvtexturestore://${textureName}`;

      if (autoRecycle) {
        // 已经是设置了texture的自动回收，所以不再需要主动调用 JsvTextureStoreApi.deleteTexture 来释放内存
      }
      doAnim();
    },
    true // 自动回收, 不填也行，默认为true
  );
};

//截屏处理
const slotRootRef = shallowRef(null);

onMounted(() => {
  window.JsvCoreApi.enableFpsDisplay(true);
});

onUnmounted(() => {
  if (vNextTickStartAnimTimer != -1) {
    clearTimeout(vNextTickStartAnimTimer);
    vNextTickStartAnimTimer = -1;
  }

  window.JsvCoreApi.enableFpsDisplay(false);
});
onBeforeUnmount(() => {
  cStyleShell.removeRule("contract");
  cStyleShell.removeRule("release");
});

defineExpose({
  switcher,
});
</script>
<template>
  <div
    :style="{
      left: props.left,
      top: props.top,
    }"
  >
    <div
      v-if="rFlag"
      :style="{
        width: props.width,
        height: props.height,
        animation: `${rAniStr} ${props.time}s`,
        transformOrigin: vTransformDirection,
      }"
      @animationend="props.onAnimEnd"
    >
      <jsv-frag-shader-view
        ref="rWidgetRef"
        :style="{
          width: props.width,
          height: props.height,
        }"
        :duration="rShaderInfo.duration"
        :shaderStr="rShaderInfo.shader"
        :autoplay="false"
        :textures="rShaderInfo.textures"
        :onEnd="rShaderInfo.onEnd"
      >
      </jsv-frag-shader-view>
    </div>
    <div
      v-if="!rShow"
      :style="{
        width: 1,
        height: 1,
        overflow: 'hidden',
      }"
    >
      <div
        ref="slotRootRef"
        :style="{
          width: props.width,
          height: props.height,
        }"
      >
        <slot></slot>
      </div>
    </div>
    <div
      v-else
      ref="slotRootRef"
      :style="{
        width: props.width,
        height: props.height,
      }"
    >
      <slot></slot>
    </div>
  </div>
</template>
