<template>
  <view class="control-container">
    <custom-card>
      <block slot="backText">{{ title }}</block>
    </custom-card>
    <view class="control-content" v-if="leftList.length > 0">
      <view class="control-list-left">
        <view
          class="control-list-left-item"
          v-for="(item, index) in leftList"
          :key="index"
          @click="controlClick(index)"
          :class="{ 'control-list-left-item-active': index === activeIndex }"
        >
          {{ item.sfDisplayname }}
        </view>
      </view>
      <view class="control-list-right">
        <view
          v-for="(item, index) in deviceList"
          class="control-list-right-item"
          :class="item.sfType == '10' ? 'control-list-right-items' : ''"
          :key="index"
        >
          <view style="display: flex; align-items: center;" v-if="item.sfType != '10'">
            <view class="control-list-right-item-icon">
              <image
                :src="item.sfType == '3' ? stir : solenoidValve"
                class="solenoid-valve"
              />
            </view>
            <view class="control-list-right-item-title">{{
              item.sfDisplayname || item.sfName
            }}</view>
            <view class="control-list-right-item-action">
              <u-switch
                :value="item.value == 1 ? true : false"
                @change="()=>changeSwitch(item)"
                activeColor="#0BBC58"
                size="40"
                inactiveColor="rgb(230, 230, 230)"
              ></u-switch>
            </view>
          </view>
          <view v-else style="width:100%">
            <view class="control-list-right-item-icon">
              <image
                :src="getSrc(item)"
                class="solenoid-valve"
              />
              <text style="margin-left:6rpx">
                {{ 
                  item.sfDisplayname || item.sfName 
                }}
              </text>
            </view>
            <view class="control-list-right-item-actions">
             <text style="color:#999999">状态 </text>
              <view class="control-list-right-item-actions-status">
                <view
                  class="status-item"
                  :class="item.value == '1'?'status-item-open':''"
                  @click="()=>changeStatus(item, '1')"
                >开</view>
                <view
                  class="status-item" 
                  :class="item.value == '0'?'status-item-pause':''" 
                  @click="()=>changeStatus(item, '0')"
                >停</view>
                <view 
                  class="status-item status-item-close-label"
                  :class="item.value == '2'?'status-item-close':''"
                  @click="()=>changeStatus(item, '2')"
                >关</view>
              </view>
            </view>
          </view>
        </view>
        <u-empty v-if="deviceList.length === 0" text="暂无数据"></u-empty>
      </view>
    </view>
    <u-empty v-else text="暂无数据"></u-empty>
  </view>
</template>
<script>
import solenoidValve from './assets/solenoidValve.png';
import stir from './assets/stir.png';
import solenoidValveGray from './assets/solenoidValveGray.png';
import solenoidValveStop from './assets/solenoidValveStop.png';
import borderRadius from './assets/borderRadius.png';

export default {
  name: 'control',
  data() {
    return {
      activeIndex: 0,
      value: false,
      solenoidValve,
      solenoidValveGray,
      solenoidValveStop,
      stir,
      borderRadius,
      title: '手动控制',
      leftList: [],
      deviceList: [],
      devBid: '',
      ws: null,
      heartbeatTimer: null,
      webSockedData: null,
      dataArray: [],
      info: null,
      sfToken: '',
      entityId: '',
      reconnectCount: 0,
    };
  },
  methods: {
    getSrc(item){
      if(item.value == '1'){
        return this.solenoidValve;
      }else if(item.value == '0'){
        return this.solenoidValveStop;
      }else if(item.value == '2'){
        return this.solenoidValveGray;
      }
    },
    initWebSocket() {
      const url = 'wss://things.ysiot.net:18080/api/ws';
      this.ws = uni.connectSocket({
        url: url,
        success: () => {
          console.log('WebSocket 连接初始化成功');
        }
      });

      uni.onSocketOpen(() => {
        console.log('WebSocket 已连接');
        // 发送测试参数
        const testParams = {
          cmds: [
            {
              type: 'TIMESERIES',
              entityType: 'DEVICE',
              entityId: this.entityId,
              scope: 'LATEST_TELEMETRY',
              cmdId: 1
            }
          ],
          authCmd: {
            cmdId: 0,
            token: this.sfToken
          }
        };
        console.log('发送测试参数:', testParams);
        uni.sendSocketMessage({
          data: JSON.stringify(testParams)
        });

        // 心跳：每 30 秒 ping 一次
        this.heartbeatTimer = setInterval(() => {
          uni.sendSocketMessage({
            data: JSON.stringify({ type: 'ping' })
          });
        }, 30 * 1000);
      });

      uni.onSocketMessage((evt) => {
        try {
          const data = JSON.parse(evt.data);
          this.webSockedData = data;
          // 收到实时数据后刷新右侧组件
            if(this.dataArray.length){
              this.mergeTwoObject(this.dataArray,this.webSockedData?.data);
              this.initData(this.dataArray);
            }
        } catch (e) {
          console.error('WebSocket 消息解析失败', e);
        }
      });

      uni.onSocketError((e) => {
        console.error('WebSocket 错误', e);
      });

      uni.onSocketClose(() => {
        console.warn('WebSocket 已断开，3 秒后尝试重连');
        clearInterval(this.heartbeatTimer);
        this.reconnectCount = (this.reconnectCount || 0) + 1;
        if (this.reconnectCount <= 10) {
          setTimeout(() => this.initWebSocket(), 3000);
        } else {
          console.warn('WebSocket 重连次数已达上限，停止重连');
        }
      });
    },
    getChecked(item) {
      return item.value == 1 ? true : false;
    },
    
    mergeTwoObject(firstObject, secondObject) {
      // 构建 sfCode 到对象的映射，实现 O(1) 查找
      const sfCodeMap = new Map();
      
      // 递归构建映射
      const buildMap = (items) => {
        for (const item of items) {
          if (item.sfCode) {
            sfCodeMap.set(item.sfCode, item);
          }
          if (item.childrenList && item.childrenList.length) {
            buildMap(item.childrenList);
          }
        }
      };
      
      buildMap(firstObject);
      
      // 遍历 secondObject 并更新值
      for (const key in secondObject) {
        let newKey = '';
        if(key.includes('GHChannelDev:ChannelParamSet')){
          newKey = key + ':Status';
          const item = sfCodeMap.get(newKey);
          if (item) {
            const params = JSON.parse(secondObject[key][0][1]);
            this.$set(item,'value',params.Status)
          }
        }else{
          const item = sfCodeMap.get(key);
          if (item) {
            this.$set(item,'value',secondObject[key][0][1])
          }
        }
      }
    },
    async sfDecvtl(data){
      const res = await this.$myRequest({
        url: '/api/v2/iot/mobile/device/sf/devctl/',
        method: 'post',
        data,
        header: {
          'Content-Type': 'application/json',
        },
      });
      if (res.code !== '000000') {
        item.value = item.value == 1 ? 0 : 1;
      }
      uni.showToast({
        title: res.msg,
        icon: 'none',
      });
    },
    changeStatus(item,index){
      const sfCode = item.sfCode;
      const params = {};
      params[sfCode] = index;
      const data = {
        devBid: this.devBid,
        data: params,
      };
      this.sfDecvtl(data)
    },
    changeSwitch(item) {
      item.value = item.value == 1 ? 0 : 1;
      const sfCode = item.sfCode;
      const params = {};
      params[sfCode] = item.value;
      const data = {
        devBid: this.devBid,
        data: params,
      };
      this.sfDecvtl(data)
    },
    controlClick(index) {
      this.activeIndex = index;
      this.deviceList = this.leftList[this.activeIndex]?.childrenList || [];
    },
    /*
      0	水源	泵类	负责水源进入管道的总泵或者阀
      1	肥料	泵类	负责肥料进入管道的总阀或者泵
      2	吸肥	泵类	控制肥料桶出肥的阀或者泵，每个肥料桶一个
      3	搅拌	泵类	肥料桶的搅拌电机或者泵 每个肥料桶一个
      4	肥料桶	泵类	肥料桶，每个施肥机有多个或者没有，不一定真实存在，只是逻辑上的概念
      5	电磁阀	无	管道最末端每个田地里控制出水的阀门
      6	传感器	无	水肥机上的 温度，压力，流速，PH EC等监测类要素
      7	灌区    无	逻辑区域，电磁阀的分组
      */
    async getsfrhinfo() {
      const res = await this.$myRequest({
        url: '/api/v2/iot/device/sf/info/',
        method: 'post',
        data: {
          devBid: String(this.devBid),
        },
      });
      this.info = res;
      this.sfToken = this.info?.sfToken;
      this.entityId = this.info?.sfUuid;
      this.closeWebSocket();
      this.initWebSocket();
    },
    // 关闭 WebSocket
    closeWebSocket() {
      clearInterval(this.heartbeatTimer);
      if (this.ws) {
        uni.closeSocket();
        this.ws = null;
      }
    },
    initData(res){
      this.deviceList = [];
      const sfCurrent = [
        {
          sfDisplayname: '水肥机',
          childrenList: [],
        },
      ];
      const irrigatedAreaList = [];
      res?.forEach((item) => {
        if (item.sfType === '0' || item.sfType === '1' || item.sfType === '2') {
          sfCurrent[0].childrenList.push(item);
        } else if (item.sfType === '4') {
          const childrenList = item?.childrenList || [];
          childrenList.forEach((child) => {
            if (
              child.sfType === '3' ||
              child.sfType === '2' ||
              child.sfType === '8'
            ) {
              sfCurrent[0].childrenList.push(child);
            }
          });
        } else if (item.sfType === '7') {
          irrigatedAreaList.push(item);
        }
      });
      this.leftList = [...sfCurrent, ...irrigatedAreaList];
      this.deviceList = this.leftList[this.activeIndex]?.childrenList || [];
    },
    async getdeviceSfStatus() {
      const res = await this.$myRequest({
        url: '/api/v2/iot/mobile/device/sf/status/',
        method: 'post',
        data: {
          devBid: this.devBid,
        },
      });
      this.dataArray = res;
      this.initData(res);
    },
  },
  onLoad(options) {
    const { devBid } = options;
    this.devBid = devBid;
    this.getdeviceSfStatus();
    this.getsfrhinfo();
  },
};
</script>
<style scoped lang="scss">
uni-page-body {
  position: relative;
  height: 100%;
}
.control-container {
  background: linear-gradient(180deg, #ffffff00 0%, #fff 23.64%, #fff 100%),
    linear-gradient(102deg, #bfeadd 6.77%, #b8f1e7 40.15%, #b9eef5 84.02%);
  height: 100%;
  width: 100%;
  overflow-x: hidden;
  overflow-y: hidden;
  .control-content {
    display: flex;
    width: 100%;
    height: calc(100% - 102rpx);
    overflow-x: hidden;
    overflow-y: auto;
    padding: 8px 0;
    border-radius: 8px 8px 0 0;
    background: #fff;
    .control-list-left {
      width: 250rpx;
      position: fixed;
      height: calc(100% - 90rpx);
      overflow-x: hidden;
      overflow-y: auto;
      .control-list-left-item {
        width: 240rpx;
        height: 96rpx;
        line-height: 96rpx;
        background: #f5f7fa;
        padding-left: 24rpx;
        color: #364d46;
        font-family: 'Source Han Sans CN VF';
        font-size: 32rpx;
        font-weight: 400;
        position: relative;
      }
      .control-list-left-item-active {
        background: #0bbc581a;
        color:#0BBC58;
        font-family: "Source Han Sans CN VF";
        font-size: 32rpx;
        font-weight: 700;
      }
    }
    .control-list-right {
      width: calc(100% - 250rpx);
      margin: 0 32rpx;
      margin-left: 280rpx;
      .control-list-right-item {
        height: 96rpx;
        display: flex;
        padding: 0rpx 16rpx;
        align-items: center;
        border-radius: 8rpx;
        background: #f5f7fa;
        margin-bottom: 22rpx;
        position: relative;
        .control-list-right-item-icon {
          display: flex;
          align-items: center;
          .solenoid-valve {
            width: 40rpx;
            height: 40rpx;
          }
        }
        .control-list-right-item-title {
          margin-left: 8rpx;
        }
        .control-list-right-item-action {
          position: absolute;
          right: 16rpx;
        }
        .control-list-right-item-actions {
          display: flex;
          align-items: center;
          margin-top: 22rpx;
          justify-content: space-between;
          .control-list-right-item-actions-status {
            display: flex;
            align-items: center;
            border-radius: 12rpx;
            background: #FFF;
            padding: 6rpx;
            margin-left: 12rpx;
            height: 50rpx;
            .status-item{
              width: 92rpx;
              height: 50rpx;
              line-height: 50rpx;
              text-align: center;
              border-radius: 8rpx;
              background: #FFF;
              color:#656565;
            }
            .status-item-close-label{
              color:#FF5951;
            }
            .status-item-open{
              background: #0BBC58;
              color: #fff;
            }
            .status-item-pause{
              background: #F8B610;
              color: #fff;
            }
            .status-item-close{
              background: #DDDFE6;
              color: #303133;
            }
          }
        }
      }
      .control-list-right-items{
        height: 172rpx;
      }
    }
  }
}
</style>
