<template>
  <div>
    <div class="progress-container" v-if="progressText">
      <text class="progress-text">{{progressText}}</text>
    </div>
    <iframe
      :id="embedId"
      v-if="url.length > 0 && pluginType != 'old-h5'"
      :src="url"
      :style="{ backgroundColor: backgroundColor, height: height }"
      ref="iframe"
      @load="onPageFinish"
    ></iframe>

    <BaseSameLayer
      class="common-view-iframe"
      v-if="pluginType == 'old-h5'"
      :hosSameLayerArgs="hosSameLayerArgs"
      embedType="native/midea-common-weex-view"
      :defaultWidth="300"
      :defaultHeight="300"
    ></BaseSameLayer>
    <!-- <image v-if="progressText.length > 0" /> -->
  </div>
</template>

<script>
import BaseSameLayer from "./baseSameLayer.vue";

const weexModule = weex.requireModule("weexModule");

export default {
  data() {
    return {
      isDebug: true, // 调试开关
      url: "",
      pluginType: "weex",
      backgroundColor: "transparent",
      progressText: "",
      embedId: `embedId_iframe_${
        Date.now().toString(36) + Math.random().toString(36).substring(2)
      }`,
      isPluginMenu: window.location.href.includes('plugin-menu'),
      height: window.location.href.includes('plugin-menu') ? '0px' : '100%',
      _resizeObserver: null,
      _heightCheckTimer: null,
      _weexRoot: null,
      _scrollerInner: null,
      _useChildrenTotalHeight: false,
      _parentElement: null, // 符合条件的父级元素
      _mutationObserver: null,
      _debounceTimer: null,
      _isInternalUpdating: false, // 内部更新锁，防止反馈回路导致反复刷新
      _pendingUpdate: false, // 锁期间是否有待处理的更新
      _applyTimer: null,
    };
  },
  components: {
    BaseSameLayer,
  },
  name: "MideaCommonWeexView",
  props: {
    hosUniqueProps: {
      type: Object,
      default() {
        return {};
      },
    },
    router: {
      type: Object,
      default() {
        return {};
      },
    },
    src: {
      type: String,
    },
    pluginData: {
      type: Object,
    },
  },
  created() {
    this.debugLog(`created: embedId=${this.embedId}, src=${this.src}`);
    weexModule.callNative(
      `webview.webHandle`,
      {
        method: "parseCommonWeexParams",
        ...this.hosUniqueProps,
        router: this.router,
        src: this.src,
        pluginData: this.pluginData,
      },
      (args) => {
        this.debugLog(`callNative 回调: args=`, args);
        if (args.progressText) {
          this.progressText = args.progressText;
          this.debugLog(`设置progressText: ${args.progressText}`);
        } else if (args.url) {
          this.url =  args.url;
          this.backgroundColor = args.pageBackgroundColor;
          this.pluginType = args.pluginType;
          this.debugLog(`设置url: ${args.url}, backgroundColor: ${args.pageBackgroundColor}, pluginType: ${args.pluginType}`);
        }
      }
    );
  },
  computed: {
    hosSameLayerArgs() {
      return {
        ...this.hosUniqueProps, // 鸿蒙原生组件独有属性
        width: this.$el.clientWidth,
        height: this.$el.clientHeight,
        data: {
          router: this.router,
          src: this.url,
          backgroundColor: this.backgroundColor,
          pluginData: this.pluginData,
        }
      };
    },
  },
  mounted() {
    this.debugLog(`mounted: embedId=${this.embedId}, isPluginMenu=${this.isPluginMenu}, height=${this.height}`);
    // this.$refs["iframe"].addEventListener('load', this.onPageFinish);
    const iframeEl = this.$refs.iframe;
    if (iframeEl) {
      this.debugLog(`找到iframe元素，添加load监听`);
      iframeEl.addEventListener("load", this.onPageFinish);
    } else {
      this.debugWarn(`未找到iframe元素`);
    }
    this.refreshWrapperAndParent();
    if (!this._wrapperEl) {
      this.debugWarn(`未找到 iframe 父级 .midea-common-weex-view`);
    }
    
    // 优化手势处理性能
    this._rafId = null;
    this._pendingGesture = null;
    this._onMessage = (event) => {
      // 处理iframe手势跨窗口传递冒泡
      if (event.data.type === 'IFRAME_GESTURE') {
        const gestureData = event.data;
        
        // touchmove 使用RAF节流，其他事件立即处理
        if (gestureData.eventType === 'touchmove') {
          this._pendingGesture = gestureData;
          if (!this._rafId) {
            this._rafId = requestAnimationFrame(() => {
              if (this._pendingGesture) {
                this.handleGestureBubble(this._pendingGesture);
                this._pendingGesture = null;
              }
              this._rafId = null;
            });
          }
        } else {
          this.handleGestureBubble(gestureData);
        }
      }
    };
    window.addEventListener("message", this._onMessage, false);
  },
  methods: {
    refreshWrapperAndParent() {
      const iframeNode = this.$refs.iframe;
      if (!iframeNode) return;
      const directParent = iframeNode.parentElement;
      // 按约定：iframe 的直接父级就是业务容器（midea-common-weex-view*）
      this._wrapperEl = directParent || null;
      this._parentElement = this._wrapperEl;
    },
    debugLog(...args) {
      if (this.isDebug) {
        console.log('cdj----plugin@midea-common-weex-view.vue', ...args);
      }
    },
    debugWarn(...args) {
      if (this.isDebug) {
        console.warn('cdj----plugin@midea-common-weex-view.vue', ...args);
      }
    },
    onPageFinish() {
      this.debugLog(`onPageFinish 触发: embedId=${this.embedId}`);
      this.refreshWrapperAndParent();
      if (this.$refs["iframe"]) {
        this.debugLog(`iframe引用存在，准备注入全局变量`);
        this.$refs["iframe"].contentWindow.$midea_harmony_native =
          window.$midea_harmony_native;
        this.$refs["iframe"].contentWindow.isIframe = true;
        this.$refs["iframe"].contentWindow.postMessage(
          JSON.stringify(window.$midea_harmony_native),
          "*"
        );
        setTimeout(()=>{
          this.debugLog(`延迟后开始监听高度: embedId=${this.embedId}`);
          this.startWeexRootHeightMonitoring();
        })
      } else {
        this.debugWarn(`onPageFinish: iframe引用不存在`);
      }
    },
    
    // 计算元素子级总高度
    calculateWeexRootChildrenHeight(el) {
      this.debugLog(`calculateWeexRootChildrenHeight 调用, element=${el ? (el.className || el.tagName) : 'null'}`);
      if (!el || !el.children || el.children.length === 0) {
        this.debugWarn(`calculateWeexRootChildrenHeight: 无子元素`);
        return 0;
      }
      
      const children = Array.from(el.children);
      let maxBottom = 0;
      let minTop = Infinity;
      let totalOffsetHeight = 0;
      
      const parentRect = el.getBoundingClientRect();
      
      children.forEach((child, index) => {
        const rect = child.getBoundingClientRect();
        // 转换为相对于父元素的坐标，避免视口绝对坐标中负 top 导致高度被持续放大
        const relTop = rect.top - parentRect.top;
        const relBottom = rect.bottom - parentRect.top;
        this.debugLog(`子级 ${index}: top=${relTop}, bottom=${relBottom}, height=${rect.height}`);
        if (rect.height > 0) {
          maxBottom = Math.max(maxBottom, relBottom);
          minTop = Math.min(minTop, Math.max(0, relTop)); // 负偏移从0算起，不向上扩展
        }
        totalOffsetHeight += (child.offsetHeight || 0);
      });
      
      // 优先使用相对坐标计算高度，不受视口滚动或容器偏移影响
      let height = (maxBottom > minTop) ? (maxBottom - minTop) : 0;
      
      this.debugLog(`计算高度详情: rectHeight=${height}, totalOffsetHeight=${totalOffsetHeight}, parentRectTop=${parentRect.top}`);
      
      // 如果 rect 计算结果不理想，使用 offsetHeight 累积作为参考
      if (height <= 0) {
        height = totalOffsetHeight;
      }

      // 结合元素本身尺寸指标，减少某些内核下 getBoundingClientRect 低估问题
      // const selfRect = parentRect.height || 0;
      // const selfScroll = el.scrollHeight || 0;
      // const selfOffset = el.offsetHeight || 0;
      // const selfClient = el.clientHeight || 0;
      // height = Math.max(height, selfRect, selfScroll, selfOffset, selfClient);
      
      return height;
    },
    
    // 监听 iframe 内容高度变化
    startWeexRootHeightMonitoring() {
      this.debugLog(`startWeexRootHeightMonitoring 开始: embedId=${this.embedId}`);
      let attempts = 0;
      const maxAttempts = 15;
      
      this._heightCheckTimer = setInterval(() => {
        attempts++;
        this.debugLog(`查找元素尝试 ${attempts}/${maxAttempts}`);
        
        const iframe = document.getElementById(this.embedId);
        if (!iframe) return;

        try {
          const doc = iframe.contentDocument || iframe.contentWindow.document;
          let target = null;

          // 1. 优先找 weex-scroller-inner 及其内部的 weex-root
          const scroller = doc.querySelector('.weex-scroller-inner');
          if (scroller) {
            this.debugLog(`找到 .weex-scroller-inner`);
            target = scroller.querySelector('.weex-root') || scroller.children[0];
          } else {
            // 2. 备选找全局 weex-root
            target = doc.querySelector('.weex-root');
          }

          if (!target) {
            if (attempts >= maxAttempts) {
              clearInterval(this._heightCheckTimer);
              this.debugWarn(`达到最大尝试次数，未找到目标元素`);
            }
            return;
          }

          const height = this.calculateWeexRootChildrenHeight(target);
          this.debugLog(`尝试计算高度: ${height}px, 目标元素: ${target.className || target.tagName}`);

          if (height > 0 || attempts >= maxAttempts) {
            clearInterval(this._heightCheckTimer);
            if (height > 0) {
              this._weexRoot = target;
              this._useChildrenTotalHeight = true;
              this.updateIframeHeightFromElement(target);
              this.setupObservers(target);
            } else {
              this.debugWarn(`高度始终为0，停止尝试`);
            }
          }
        } catch (e) {
          this.debugWarn(`监控过程异常:`, e.message);
          if (attempts >= maxAttempts) clearInterval(this._heightCheckTimer);
        }
      }, 200);
    },

    setupObservers(target) {
      this.debugLog(`设置 Observers: target=${target ? (target.className || target.tagName) : 'null'}`);
      
      const onUpdate = () => {
        // 如果正在内部更新高度引起的重排，记录下有变化发生，然后直接跳过
        if (this._isInternalUpdating) {
          this._pendingUpdate = true;
          return;
        }

        this.debugLog(`变化触发更新`);
        if (this._debounceTimer) {
          clearTimeout(this._debounceTimer);
        }
        this._debounceTimer = setTimeout(() => {
          this.debugLog(`防抖后执行更新`);
          this.updateIframeHeightFromElement(target);
          this._debounceTimer = null;
        }, 200);
      };

      if (this._resizeObserver) this._resizeObserver.disconnect();
      if (this._mutationObserver) this._mutationObserver.disconnect();

      this._resizeObserver = new ResizeObserver(() => onUpdate());
      this._mutationObserver = new MutationObserver(() => onUpdate());

      if (target) {
        this._resizeObserver.observe(target);
        this._mutationObserver.observe(target, { childList: true, subtree: true, attributes: true });
        // 监听直接子节点
        Array.from(target.children).forEach(child => this._resizeObserver.observe(child));
      }
    },
    
    // 根据元素高度更新 iframe 高度
    updateIframeHeightFromElement(element) {
      this.debugLog(`updateIframeHeightFromElement 调用: element=${!!element}, embedId=${this.embedId}`);
      // 每次更新前刷新一次，防止动态重渲染导致引用丢失
      this.refreshWrapperAndParent();
      if (!element) {
        this.debugWarn(`updateIframeHeightFromElement: element为空`);
        return;
      }
      
      let elementHeight = 0;
      
      // 如果标记了使用子元素总高度，且 weexRoot 存在，计算所有子元素的总高度
      if (this._useChildrenTotalHeight && this._weexRoot) {
        elementHeight = this.calculateWeexRootChildrenHeight(this._weexRoot);
        this.debugLog(`使用子元素总高度: ${elementHeight}px`);
      }
      
      // 如果子元素总高度为0或未使用，则使用元素本身的高度
      if (elementHeight <= 0) {
        const offsetHeight = element.offsetHeight || 0;
        const clientHeight = element.clientHeight || 0;
        elementHeight = offsetHeight || clientHeight;
        this.debugLog(`使用元素本身高度: offsetHeight=${offsetHeight}, clientHeight=${clientHeight}, 最终=${elementHeight}px`);
      }
      
      this.debugLog(`计算得到elementHeight=${elementHeight}px`);
      
      if (elementHeight > 0) {
        // isPluginMenu=false：始终不按视口裁剪，保持原逻辑不变。
        // isPluginMenu=true：改为不裁剪，避免多组件时下方 iframe 被裁成一条线、且裁剪值同步到父级压扁整块。
        let maxHeight = Number.POSITIVE_INFINITY;
        if (this.isPluginMenu) {
          maxHeight = Number.POSITIVE_INFINITY; // 仅对 plugin-menu 取消视口裁剪，不影响 isPluginMenu=false
        }
        this.debugLog(`maxHeight=${maxHeight} (isPluginMenu=${this.isPluginMenu})`);

        const finalHeight = elementHeight > maxHeight ? maxHeight : elementHeight;
        this.debugLog(`finalHeight=${finalHeight}px (elementHeight=${elementHeight}, maxHeight=${maxHeight})`);

        // 更新 iframe 高度（考虑 weex scale）
        const scale = weex.config.env.scale || 1;
        let newHeightValue = finalHeight / scale;

        // 父级有 style 设置的高度时：若 iframe 计算高度偏小，直接用父级高度
        // 关键：直接解析 inline style 字符串（rem/px），而不用 getBoundingClientRect，
        // 避免因为内容撑大或旧代码写入导致取到错误的"当前渲染高度"
        if (this._wrapperEl) {
          try {
            const inlineHeight = this._wrapperEl.style && this._wrapperEl.style.height;
            const parentHasExplicitHeight = !!(
              inlineHeight && inlineHeight !== "auto" && inlineHeight !== "100%"
            );
            if (parentHasExplicitHeight) {
              const wrapperCssPx = this._wrapperEl.getBoundingClientRect().height || 0;
              const wrapperWeexVp = wrapperCssPx / scale;
              this.debugLog(`父级有显式高度: inlineHeight=${inlineHeight}, wrapperCssPx=${wrapperCssPx}, wrapperWeexVp=${wrapperWeexVp}, calcWeexVp=${newHeightValue}`);
              if (wrapperWeexVp > 0 && newHeightValue < wrapperWeexVp) {
                this.debugLog(`iframe 偏小，使用父级高度: ${newHeightValue} -> ${wrapperWeexVp}`);
                newHeightValue = wrapperWeexVp;
              }
            }
          } catch (e) {
            this.debugWarn("读取父级高度失败:", e);
          }
        }

        const newHeight = `${newHeightValue}px`;
        this.debugLog(`计算newHeight=${newHeight} (finalHeight=${finalHeight}, scale=${scale}), 当前height=${this.height}`);
        
        // 增大误差容忍度：如果差距小于 3px，认为没有实质变化，不触发属性更新。
        // 3px 足以过滤 Weex 在处理 rem 布局时产生的浮点数舍入误差。
        const currentHeightValue = parseFloat(this.height) || 0;
        if (Math.abs(currentHeightValue - newHeightValue) < 3 && this.height !== '0px') {
          this.debugLog(`⚠️ 高度微小抖动(${Math.abs(currentHeightValue - newHeightValue)}px)，忽略微调以稳定布局`);
          return;
        }

        if (this.height !== newHeight) {
          this._isInternalUpdating = true; // 加锁
          
          // 使用异步应用机制，确保在一轮布局周期内只应用最后一次高度结果
          if (this._applyTimer) clearTimeout(this._applyTimer);
          this._applyTimer = setTimeout(() => {
            this.height = newHeight;
            this.debugLog(`✅ [FINAL] iframe 高度已应用: ${newHeight} (embedId: ${this.embedId})`);
            
            // 给 Weex 引擎留出更充分的布局响应时间，随后解锁并检查是否有遗漏
            setTimeout(() => {
              this._isInternalUpdating = false;
              if (this._pendingUpdate) {
                this._pendingUpdate = false;
                this.debugLog(`补测锁期间拦截的变化`);
                this.updateIframeHeightFromElement(element);
              }
            }, 600);
          }, 50); // 极短的延迟即可实现一轮内的覆盖
        } else {
          this.debugLog(`⚠️ 高度未变化，不更新 (当前=${this.height}, 新值=${newHeight})`);
        }
        
      } else {
        this.debugWarn(`⚠️ elementHeight <= 0，不更新高度 (elementHeight=${elementHeight})`);
      }
    },
    handleGestureBubble(gestureData) {
      const iframeEl = this.$refs.iframe;
      if (!iframeEl) return;

      const rect = iframeEl.getBoundingClientRect();
      const offsetX = rect.left;
      const offsetY = rect.top;
      const pageOffsetX = offsetX + window.pageXOffset;
      const pageOffsetY = offsetY + window.pageYOffset;
      
      // 创建Touch对象并转换坐标
      const createTouches = (touchesData) => touchesData.map(t => new Touch({
        identifier: t.identifier,
        target: iframeEl,
        clientX: t.clientX + offsetX,
        clientY: t.clientY + offsetY,
        screenX: t.screenX,
        screenY: t.screenY,
        pageX: t.pageX + pageOffsetX,
        pageY: t.pageY + pageOffsetY,
        radiusX: t.radiusX || 0,
        radiusY: t.radiusY || 0,
        rotationAngle: t.rotationAngle || 0,
        force: t.force || 0
      }));

      try {
        iframeEl.dispatchEvent(new TouchEvent(gestureData.eventType, {
          bubbles: true,
          cancelable: true,
          composed: true,
          touches: createTouches(gestureData.touches),
          targetTouches: createTouches(gestureData.targetTouches),
          changedTouches: createTouches(gestureData.changedTouches),
          ctrlKey: gestureData.ctrlKey,
          shiftKey: gestureData.shiftKey,
          altKey: gestureData.altKey,
          metaKey: gestureData.metaKey
        }));
      } catch (e) {
        this.debugWarn('手势事件冒泡失败:', e);
      }
    },
  },
  beforeDestroy() {
    this.debugLog(`beforeDestroy: embedId=${this.embedId}`);
    // 清理 ResizeObserver
    if (this._resizeObserver) {
      this.debugLog(`清理 ResizeObserver`);
      this._resizeObserver.disconnect();
      this._resizeObserver = null;
    }

    // 清理 MutationObserver
    if (this._mutationObserver) {
      this.debugLog(`清理 MutationObserver`);
      this._mutationObserver.disconnect();
      this._mutationObserver = null;
    }
    
    // 清理定时器
    if (this._heightCheckTimer) {
      this.debugLog(`清理高度检查定时器`);
      clearInterval(this._heightCheckTimer);
      this._heightCheckTimer = null;
    }

    // 清理防抖定时器
    if (this._debounceTimer) {
      this.debugLog(`清理防抖定时器`);
      clearTimeout(this._debounceTimer);
      this._debounceTimer = null;
    }

    if (this._applyTimer) {
      clearTimeout(this._applyTimer);
      this._applyTimer = null;
    }
    
    // 清理引用
    this._weexRoot = null;
    this._scrollerInner = null;
    this._useChildrenTotalHeight = false;
    
    // 清理RAF避免内存泄漏
    if (this._rafId) {
      this.debugLog(`清理RAF`);
      cancelAnimationFrame(this._rafId);
      this._rafId = null;
    }
    
    // 清理消息监听
    if (this._onMessage) {
      this.debugLog(`清理消息监听`);
      window.removeEventListener("message", this._onMessage, false);
    }
    this.debugLog(`beforeDestroy 完成`);
  },
};
</script>

<style scoped>
.common-view-iframe {
  height: 100%;
}
.progress-container {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 10;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
.progress-loading {
  width:80px;
  height:80px;
  display: block;
  margin-bottom: 40px;
}
.progress-text {
  font-size: 24px;
  color: #333;
  text-align: center;
  font-weight: 400;
}
</style>