<template>
  <div class="bl___camera zIndexByJs"
       :data-zIndex="zIndex"
       bili-type="camera"
       :bili-id="biliId"
  >
  </div>
</template>

<script>
import {judgeEnv, compareVersion} from '../util/logic';

export default {
  name: 'Bili_Camera',
  props: {
    "id": {
      type: String,
      default: ''
    },
    "mode": {
      type: String,
      default: 'normal'
    },
    "resolution": {
      type: String,
      default: 'medium'
    },
    "devicePosition": {
      type: String,
      default: 'back'
    },
    "flash": {
      type: String,
      default: 'auto'
    },
    "frameSize": {
      type: String,
      default: 'medium'
    },
    "zIndex": {
      type: Number,
      default: 0
    }
  },
  // 监控属性变化
  watch: {
    devicePosition: function (value) {
      this._attrUpdate('devicePosition', value);
    },
    flash: function (value) {
      this._attrUpdate('flash', value);
    },
    frameSize: function (value) {
      this._attrUpdate('frameSize', value);
    }
  },
  data() {
    return {
      cameraInstance: null,
      observer: null,
      systemInfo: null,
      biliId: '',
      cacheMsg: null,
      styles: {}
    };
  },
  created() {
    let _env = judgeEnv().env;
    this.biliId = this._uid;
    if (_env === 'Service') {
      if (!global.__biliComponentData.camera) global.__biliComponentData.camera = {};
      const pageId = global.__biliCacheData.getCurrentPageId();
      if (!global.__biliComponentData.camera[pageId]) global.__biliComponentData.camera[pageId] = {};
      if (!global.__biliComponentData.camera[pageId].componentId) global.__biliComponentData.camera[pageId].componentId = this._uid;
    }
  },
  mounted() {
    let _env = judgeEnv().env;
    if (_env === 'Render') {
        let _systemInfo = bl.getSystemInfoSync()
        if (this._isSupport()) {
            const that = this;
            this.systemInfo = bl.getSystemInfoSync();
            SmallApp.computeIndex();
            SmallApp.waitStyleOver().then(()=>{
                that.styles = that._computeStyle();
                SmallApp.nativeComponent({
                    ...that._getBasicData(),
                    actionType: "create",
                    mode: that.mode,
                    resolution: that.resolution,
                    devicePosition: that.devicePosition,
                    flash: that.flash,
                    frameSize: that.frameSize,
                    styles: that._computeStyle()
                    
                });
            });
            this._watchStyle();
        } else {
          if (judgeEnv().isDowngrade) {
            this.$emit('error', {
              detail: 'camera not supported in webview'
            })
          } else {
            this.$emit('error', {
              detail: `camera not supported in this sdkversion: ${_systemInfo.SDKVersion}`
            })
          }
        }
    }
  },
  beforeDestroy() {
    let _env = judgeEnv().env;
    if (_env === 'Render') {
      if (this._isSupport()) {
          SmallApp.nativeComponent({
              ...this._getBasicData(),
              actionType: "destroy"
          });
          this.observer.disconnect();
      }
    }
    else {
      // 删除映射
      const pageId = global.__biliCacheData.getCurrentPageId();
      delete global.__biliComponentData.camera[pageId]
    }
  },
  methods: {
    _isSupport() {
      let _systemInfo = bl.getSystemInfoSync()
      return !judgeEnv().isDowngrade && compareVersion(_systemInfo.SDKVersion,'3.79.0') >= 0
    },
    // handleMessage，作为事件的触发，该方法NA会直接调用。
    handleMessage(message) {
      if (message.type === 'native-component') {
        this.$emit(message.event.type, message.event);
      }
    },
    _getBasicData(){
        return {
            type: "native-component",
            id: this._uid,
            name: "camera",
            zIndex: Number(this.$el.getAttribute('B-zIndex'))
        }
    },
    _attrUpdate(key, value) {
      if(this._isSupport()) {
        SmallApp.nativeComponent({
            ...this._getBasicData(),
            actionType: "attrUpdate",
            [key]: value
        });
      }
    },
    updateStyles() {
        let positionInfo = this.$el.getBoundingClientRect();
        let styleInfo = window.getComputedStyle(this.$el);
        let isFixed = styleInfo.getPropertyValue("position") === "fixed";
        const newStyles = {
            x: isFixed ? positionInfo.left : positionInfo.left + SmallApp.getScrollData('left'),
            y: isFixed ? positionInfo.top : positionInfo.top + SmallApp.getScrollData('top'),
            width: positionInfo.width,
            height: positionInfo.height,
            fixed: isFixed,
            hidden: styleInfo.getPropertyValue("display") === "none",
        };
        const diffStyles = this.diffJson(this.styles, newStyles);
        if (diffStyles) {
            this.styles = newStyles;
            SmallApp.nativeComponent({
                ...this._getBasicData(),
                actionType: "styleUpdate",
                styles: diffStyles
            });
        }
    },
    // 改变属性，且通知Native
    changeAttribute(attrKey, attrValue) {
      // render层执行
      if (judgeEnv().env === 'Render') {
        this.cameraInstance.updateAttr(attrKey, attrValue);
      }
    },
    // 监控整个body变化，重新计算样式
    _watchStyle() {

      const that = this;
      // 监控整个body变化，如有变化则重新计算样式是否有变动。做节流优化。
      this.observer = new MutationObserver(() => {

        SmallApp.waitStyleOver().then(() => {
          that.updateStyles();
        });
      });

      this.observer.observe(document.body, {
        attributes: true,
        childList: true,
        characterData: true,
        subtree: true
      });
    },
    _computeStyle() {
        let styleInfo = global.getComputedStyle(this.$el);
        let positionInfo = this.$el.getBoundingClientRect();
        let isFixed = styleInfo.getPropertyValue("position") === "fixed";
        const result = {
            x: isFixed ? positionInfo.left : positionInfo.left + SmallApp.getScrollData('left'),
            y: isFixed ? positionInfo.top : positionInfo.top + SmallApp.getScrollData('top'),
            width: positionInfo.width,
            height: positionInfo.height,
            fixed: isFixed,
            hidden: styleInfo.getPropertyValue("display") === "none",
        }
        return result;
    },
    disconnectObserver() {
      this.observer && this.observer.disconnect();
      this.observer = null;
    },
    diffJson(oldJson, newJson){
      if (typeof newJson !== "object" || typeof oldJson !== "object") {
          return newJson;
      }

      let diff = null;
      Object.keys(newJson).forEach((k) => {
          if (oldJson[k] !== newJson[k]) {
              if (!diff) {
                  diff = {};
              }

              diff[k] = newJson[k];
          }
      });

      return diff;
    }
  },

};
</script>

<style lang="less">
.bl___camera {
  width: 350px;
  height: 200px;
}

</style>
