<template>
  <view class="container">
    <!-- 控制设置标题 -->
    <view class="control-title">控制设置</view>
    <uni-section title="请选择大棚：" titleFontSize="18px" type="line">
      <view class="uni-px-5 uni-pb-5">
        <uni-data-select v-model="value" :localdata="range" @change="change"></uni-data-select>
      </view>
    </uni-section>


    <uni-section title="实时温湿度" titleFontSize="16px" type="line"  v-if="value!== 1">
      <template v-slot:right >
        {{ temp }}
      </template>

        <view>
          <view class="uni-flex_control uni-row" >
            <view class="text uni-flex_control_one uni-view">
              <text class="data" :style="fontStyle">{{ liveData.temp1 }}<p v-if=(testNumber(liveData.temp1)) class="tempStyle">℃</p></text>
              <text class="data">温度1</text>
            </view>
            <view class="text uni-flex_control_one uni-view">
              <text class="data" :style="fontStyle">{{ liveData.temp2 }}<p v-if=(testNumber(liveData.temp2)) class="tempStyle">℃</p></text>
              <text class="data">温度2</text>
            </view>
            <view class="text uni-flex_control_one uni-view">
              <text class="data" :style="fontStyle">{{ liveData.temp3 }}<p v-if=(testNumber(liveData.temp3)) class="tempStyle">℃</p></text>
              <text class="data">温度3</text>
            </view>
            <view class="text uni-flex_control_one uni-view">
              <text class="data" :style="fontStyle">{{ liveData.temp4 }}<p v-if=(testNumber(liveData.temp4)) class="tempStyle">℃</p></text>
              <text class="data">温度4</text>
            </view>
          </view>

          <view class="uni-flex_control uni-row" >
            <view class="text uni-flex_control_two uni-view">
              <text class="data" :style="fontStyle">{{ liveData.humi1 }}<p v-if=(testNumber(liveData.humi1)) class="humiStyle"> %RH</p></text>
              <text class="data">湿度1</text>
            </view>
            <view class="text uni-flex_control_two uni-view">
              <text class="data" :style="fontStyle">{{ liveData.humi2 }}<p v-if=(testNumber(liveData.humi2)) class="humiStyle"> %RH</p></text>
              <text class="data">湿度2</text>
            </view>
            <view class="text uni-flex_control_two uni-view">
              <text class="data" :style="fontStyle">{{ liveData.humi3 }}<p v-if=(testNumber(liveData.humi3)) class="humiStyle"> %RH</p></text>
              <text class="data">湿度3</text>
            </view>
            <view class="text uni-flex_control_two uni-view">
              <text class="data" :style="fontStyle">{{ liveData.humi4 }}<p v-if=(testNumber(liveData.humi4)) class="humiStyle"> %RH</p></text>
              <text class="data">湿度4</text>
            </view>
          </view>
        </view>


    </uni-section>

    <uni-section title="设备控制" titleFontSize="16px" type="line" v-if="value!== 1">

      <!-- 卷膜/卷被卡片容器（2列栅格布局） -->
      <view class="card-grid">
        <!-- 卷被开卡片 -->
        <view class="control-card" @click="handleCardClick(1-status.jbk, 'jbk')">
          <view class="card-text">
            <text class="card-main">卷被开</text>
            <text class="card-sub">{{ show.jbk }}</text>
          </view>
          <view class="card-icon" :class="{ active: status.jbk === 1 }">
            <uni-icons :type=" (status.jbk === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
          </view>
        </view>

        <!-- 卷被关卡片 -->
        <view class="control-card" @click="handleCardClick(1-status.jbg,'jbg')">
          <view class="card-text">
            <text class="card-main">卷被关</text>
            <text class="card-sub">{{ show.jbg }}</text>
          </view>
          <view class="card-icon" :class="{ active: status.jbg === 1 }">
            <uni-icons :type=" (status.jbg === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
          </view>
        </view>

        <!-- 卷膜1开卡片 -->
        <view class="control-card" @click="handleCardClick(1-status.jm1k, 'jm1k')">
          <view class="card-text">
            <text class="card-main">卷膜1开</text>
            <text class="card-sub">{{ show.jm1k }}</text>
          </view>
          <view class="card-icon" :class="{ active: status.jm1k === 1 }">
            <uni-icons :type="(status.jm1k === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
          </view>
        </view>

        <!-- 卷膜1关卡片 -->
        <view class="control-card" @click="handleCardClick(1-status.jm1g, 'jm1g')">
          <view class="card-text">
            <text class="card-main">卷膜1关</text>
            <text class="card-sub">{{ show.jm1g }}</text>
          </view>
          <view class="card-icon" :class="{ active: status.jm1g === 1 }">
            <uni-icons :type="(status.jm1g === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
          </view>
        </view>

        <!-- 卷膜2卡片 -->
        <view class="control-card" @click="handleCardClick(1-status.jm2k, 'jm2k')">
          <view class="card-text">
            <text class="card-main">卷膜2开</text>
            <text class="card-sub">{{ show.jm2k }}</text>
          </view>
          <view class="card-icon" :class="{ active: status.jm2k === 1 }">
            <uni-icons :type="(status.jm2k === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
          </view>
        </view>

        <!-- 卷膜2关卡片 -->
        <view class="control-card" @click="handleCardClick(1-status.jm2g, 'jm2g')">
          <view class="card-text">
            <text class="card-main">卷膜2关</text>
            <text class="card-sub">{{ show.jm2g }}</text>
          </view>
          <view class="card-icon" :class="{ active: status.jm2g === 1 }">
            <uni-icons :type="(status.jm2g === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
          </view>
        </view>
        <!-- 卷膜3开卡片 -->
        <view class="control-card" @click="handleCardClick(1-status.jm3k, 'jm3k')">
          <view class="card-text">
            <text class="card-main">卷膜3开</text>
            <text class="card-sub">{{ show.jm3k }}</text>
          </view>
          <view class="card-icon" :class="{ active: status.jm3k === 1 }">
            <uni-icons :type="(status.jm3k === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
          </view>
        </view>

        <!-- 卷膜3关卡片 -->
        <view class="control-card" @click="handleCardClick(1-status.jm3g, 'jm3g')">
          <view class="card-text">
            <text class="card-main">卷膜3关</text>
            <text class="card-sub">{{ show.jm3g }}</text>
          </view>
          <view class="card-icon" :class="{ active: status.jm3g === 1 }">
            <uni-icons :type="(status.jm3g === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
          </view>
        </view>
      </view>
    </uni-section>
  </view>
</template>

<script>
import mqtt from 'mqtt'
import UniDatetimePicker
  from "../../uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue";
import { findDtuDataByInfo } from "@/api/system/data";

export default {
  dicts: ['sys_data_map'],
  components: {
    UniDatetimePicker
  },
  data() {
    return {
      temp: "",
      mqttConfig: {
        host: '1.94.254.176',
        port: 9001,
        clientId: 'uniapp_mqtt_' + Math.random().toString(16).substr(2, 8),
        username: 'admin',
        password: 'Admin#12345678',
        subscribeTopic:'/up',
      },
      value: 1,
      range: [{
        "value": '864865085016294',
        "text": "十方北棚"
      }, {
        "value": '864536071808560',
        "text": "七方北棚",
      }, {
        "value": '864865085008135',
        "text": "八方北棚"
      }],
      imei:'',
      publishTopic: '/down',
      title:'',
      message: {},
      connected:false,
      liveData: {
        temp1: '数据加载中...',
        temp2: '数据加载中...',
        temp3: '数据加载中...',
        temp4: '数据加载中...',
        humi1: '数据加载中...',
        humi2: '数据加载中...',
        humi3: '数据加载中...',
        humi4: '数据加载中...'
      },
      // 卡片状态（模拟后端返回数据）
      show: {
        jbk: "暂停",
        jbg: "暂停",
        jm1k: "暂停",
        jm1g: "暂停",
        jm2k: "暂停",
        jm2g: "暂停",
        jm3k: "暂停",
        jm3g: "暂停"
      },
      deviceType: '',
      status: {
        jbk: 0,
        jbg: 0,
        jm1k: 0,
        jm1g: 0,
        jm2k: 0,
        jm2g: 0,
        jm3k: 0,
        jm3g: 0
      },
      fontStyle: ''
    };
  },
  onLoad() {
    this.title="";
    if (this.status.jbk===1) {
      this.status.jbg = 0;
    }
    if (this.status.jbg===1) {
      this.status.jbk = 0;
    }
    if (this.status.jm1k===1) {
      this.status.jm1g = 0;
    }
    if (this.status.jm2k===1) {
      this.status.jm2g = 0;
    }
    if (this.status.jm3k===1) {
      this.status.jm3g = 0;
    }
    if (this.status.jm1g===1) {
      this.status.jm1k = 0;
    }
    if (this.status.jm2g===1) {
      this.status.jm2k  = 0;
    }
    if (this.status.jm2g===1) {
      this.status.jm3k  = 0;
    }

  },
  onShow() {
    this.connectMqtt();
  },
  onUnload() {
    this.disconnectMqtt()
  },
  methods: {
    change(e) {
      this.imei = e;
      this.publishTopic = "dtu/"+this.imei+"/down";
      this.mqttConfig.subscribeTopic = "dtu/"+this.imei+"/up";
      const selectedItem = this.range.find(item => item.value === e);
      if (selectedItem) {
        this.selectedText = selectedItem.text; // 获取展示文本
        this.title= this.selectedText;
        var queryParams = {
          imei: this.imei
        }
        findDtuDataByInfo(queryParams).then(response => {
          this.liveData = {
            temp1: response.data.temp1 || '已离线...',
            temp2: response.data.temp2 || '已离线..',
            temp3: response.data.temp3 || '已离线..',
            temp4: response.data.temp4 || '已离线..',
            humi1: response.data.humi1 || '已离线..',
            humi2: response.data.humi2 || '已离线..',
            humi3: response.data.humi3 || '已离线..',
            humi4: response.data.humi4 || '已离线..'
          }
          this.temp = "最后更新时间："+response.data.time;
          this.fontStyle = 'font-size:16px;'
        })
      } else {
        this.selectedText = ''; // 无匹配项时清空
        this.title='';
        this.value=1;
      }
      this.reset();
      this.style="";
      // this.disconnectMqtt();
    },

    reset() {
      this.show = {
        jbk: "暂停",
        jbg: "暂停",
        jm1k: "暂停",
        jm1g: "暂停",
        jm2k: "暂停",
        jm2g: "暂停",
        jm3k: "暂停",
        jm3g: "暂停"
      }
      this.deviceType = '';
      this.status = {
        jbk: 0,
        jbg: 0,
        jm1k: 0,
        jm1g: 0,
        jm2k: 0,
        jm2g: 0,
        jm3k: 0,
        jm3g: 0
      };
      this.message = {};
      this.temp = '';
      this.liveData = {
        temp1: '数据加载中...',
            temp2: '数据加载中...',
            temp3: '数据加载中...',
            temp4: '数据加载中...',
            humi1: '数据加载中...',
            humi2: '数据加载中...',
            humi3: '数据加载中...',
            humi4: '数据加载中...'
      }
    },
    // 卡片点击事件（实际项目中调用接口修改状态） 功能标识
    handleCardClick(status, type) {
      // 校验
      // 定义类型与提示文案的映射关系，减少重复代码
      const tipMap = {
        'jbk': {opposite: 'jbg', name: '卷被关', op: '卷被开'},
        'jbg': {opposite: 'jbk', name: '卷被开', op: '卷被关'},
        'jm1k': {opposite: 'jm1g', name: '卷膜1关', op: '卷膜1开'},
        'jm1g': {opposite: 'jm1k', name: '卷膜1开', op: '卷膜1关'},
        'jm2k': {opposite: 'jm2g', name: '卷膜2关', op: '卷膜2开'},
        'jm2g': {opposite: 'jm2k', name: '卷膜2开', op: '卷膜2关'},
        'jm3k': {opposite: 'jm3g', name: '卷膜3关', op: '卷膜3开'},
        'jm3g': {opposite: 'jm3k', name: '卷膜3开', op: '卷膜3关'}
      };

      // 先判断类型是否在映射表中，避免无效case
      if (!tipMap[type]) return;

      const {opposite, name, op} = tipMap[type];
      // 核心校验逻辑（只写一次，无需重复）
      if (status === 1 && this.status[opposite] === 1) {
        this.$modal.msgError(`【${this.selectedText}】${name}在运行状态，不能运行${op}操作！`);
        // 此处return可保留，也可去掉（因为函数执行到这里已完成核心逻辑）
        return;
      }

      if (!this.connected) {
        // 链接mqtt
        this.connectMqtt()
      }
      if (this.value === 1) {
        this.$modal.msgError("设备控制失败！");
        console.info("大棚选取失败!")
        return;
      }
      uni.showModal({
        title: '操作提示：',
        content: '确定' + (status === 1 ? "运行" : "暂停") + '【' + this.selectedText + '】设备？',
        cancelText: '取消',
        confirmText: '确定',
        success: (res) => {
          if (res.confirm) {
            // console.info("操作功能：【"+type+"】，变更状态为："+ status)

            // // 组装消息
            this.message = JSON.stringify({[type]: status})
            // console.info("指令："+this.message+"；大棚："+this.publishTopic)
            // 控制设备
            this.publishMessage();
            // 设备回执
            this.deviceType = type;
            //todo

            // this.status[type] = this.status[type] === 0 ? 1 : 0;
            // this.show[type] = this.status[type] === 0 ? "运行" : "暂停";

          }
        }
      })
      // console.info(this.status)
    },
    connectMqtt() {
      const options = {
        clientId: this.mqttConfig.clientId,
        username: this.mqttConfig.username,
        password: this.mqttConfig.password,
        clean: true,
        connectTimeout: 4000,
        reconnectPeriod: 1000
      }

      const url = `ws://${this.mqttConfig.host}:${this.mqttConfig.port}/mqtt`

      this.client = mqtt.connect(url, options)

      this.client.on('connect', () => {
        this.connected = true
        this.client.subscribe('dtu/+/up', {qos: 0})
        this.addMessage('已连接到MQTT服务器')
      })

      this.client.on("message", this.ackMessage);

      this.client.on('error', (err) => {
        this.addMessage(`控制失败: ${err.message}`)
        this.connected = false
      })

      this.client.on('reconnect', () => {
        this.addMessage('正在重新连接...')
      })

      this.client.on('close', () => {
        this.addMessage('连接已关闭')
        this.connected = false
      })
    },

    disconnectMqtt() {
      if (this.client && this.connected) {
        this.client.end()
        this.connected = false
        this.addMessage('已断开MQTT连接')
      }
    },

    publishMessage() {
      // console.info("开始发布消息",this.connected,this.publishTopic,this.message)
      if (!this.connected || !this.publishTopic || !this.message) {
        uni.showToast({
          title: '控制设备失败',
          icon: 'none'
        })
        return
      }

      this.client.publish(this.publishTopic, this.message, (err) => {
        if (!err) {
          this.addMessage(`【指令已发送】imei: ${this.publishTopic}，指令: ${this.message}`);

        } else {
          this.addMessage(`发布失败: ${err.message}，设备：[${this.publishTopic}]`)
        }
      })

      this.message = {};
    },

    ackMessage(topic, payload) {


      // console.info("消息解析："+topic,payload)
      // 1. 先判断是否是目标订阅主题（如dtu/xxx/up）
      if (topic !== this.mqttConfig.subscribeTopic) return;

      // 2. 解析消息体（注意异常捕获）
      let msgData = {};
      try {
        msgData = JSON.parse(payload);
      } catch (e) {
        console.error("消息解析失败：", e);
        return;
      }
      // console.info("回执消息："+msgData)
      // 3. 区分“回执”和“其他内容”
      if (msgData.prop && "suc" in msgData) {
        // console.info("处理回执消息")
        // 👉 这是“指令回执”
        this.handleCommandAck(msgData, this.deviceType);
      } else {
        this.handleOtherContent(msgData,payload)
      }
    },
    addMessage(content) {

      console.info("提示消息：" + content)
    },

    // 处理指令回执的函数
    handleCommandAck(ackData, type) {
      // console.info("回执消息11111："+ackData)
      // 拿到指令字段（如jm2k）和执行状态（suc）
      const commandField = Object.keys(ackData.prop)[0]; // 这里是"jm2k"
      const commandValue = ackData.prop[commandField];   // 这里是0
      const isSuccess = ackData.suc;                     // 这里是true

      if (isSuccess) {
        this.status[type] = this.status[type] === 0 ? 1 : 0;
        this.show[type] = this.status[type] === 0 ? "运行" : "暂停";
      }
      this.deviceType = '';
      this.$modal.msgSuccess("设备操作成功！")

      // 业务逻辑：提示“指令执行成功/失败”
      console.log(`指令[${commandField}=${commandValue}]执行${isSuccess ? "成功" : "失败"}`);
      // （可匹配之前发布的指令msgId，更新UI状态）
    },

    // 处理其他内容的函数
    handleOtherContent(msgData,payload) {
      // 业务逻辑：处理传感器数据、设备状态等
      // console.log("收到其他内容：", msgData);
      // 例如：更新温湿度显示、设备在线状态等

      // 设备状态展示
      if (this.value !== 1) {
        var arr = ['jbk', "jbg", "jm1k", "jm1g", "jm2k", "jm2g", "jm3k", "jm3g"]
        const allKeysNumeric = Object.keys(msgData).some(key => arr.includes(key));
        if (allKeysNumeric) {
          // console.info(msgData)
          this.status = {...msgData}
          // 3. 遍历msgData的所有键，根据值设置this.show的对应文本
          Object.keys(msgData).forEach(key => {
            const value = msgData[key];
            // 判断值：0→暂停，1→运行，其他值可补充默认值（可选）
            this.show[key] = value === 0 ? '暂停' :  '运行';
          });
          // console.info("imei: "+this.publishTopic+"copy: ",this.status)
        }
        const allKeysNumeric2 = Object.keys(msgData).every(key => /^\d+$/.test(key));
        if (Object.keys(msgData).length > 0 && allKeysNumeric2) {

          // 你的键：温度101~104、湿度201~204（按你之前约定温度/10、湿度/10）
          const div10 = (v) => (v == null ? null : Math.round((Number(v)/10)*10)/10)

          this.liveData = {
            temp1: div10(msgData["201"]) || "已离线...",
            humi1: div10(msgData["101"]) || "已离线...",
            temp2: div10(msgData["202"]) || "已离线...",
            humi2: div10(msgData["102"]) || "已离线...",
            temp3: div10(msgData["203"]) || "已离线...",
            humi3: div10(msgData["103"]) || "已离线...",
            temp4: div10(msgData["204"]) || "已离线...",
            humi4: div10(msgData["104"]) || "已离线...",
          }
          // 调用函数获取并输出格式化后的当前时间
          this.temp = "最新更新时间：" + this.getCurrentTime();
          this.fontStyle = 'font-size:16px;'
        }

      }
    },

    /**
     * 获取格式化后的当前时间
     * @returns {string} 格式为 YYYY-MM-DD HH:mm:ss 的当前时间
     */
    getCurrentTime() {
      const now = new Date();

      // 获取年、月、日（补零确保两位数）
      const year = now.getFullYear();
      const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从 0 开始，需 +1
      const day = String(now.getDate()).padStart(2, '0');

      // 获取时、分、秒（补零确保两位数）
      const hours = String(now.getHours()).padStart(2, '0');
      const minutes = String(now.getMinutes()).padStart(2, '0');
      const seconds = String(now.getSeconds()).padStart(2, '0');

      // 拼接成标准格式
      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
    },

    testNumber(data) {
      const reg = /^-?\d+(\.\d+)?$/;
      return reg.test(String(data).trim());
    }
  },
  onHide() {
    this.disconnectMqtt();
  },
  beforeDestroy() {
    if (this.client) {
      this.client.end()
    }
  },


};
</script>

<style scoped>
.container {
  padding: 20rpx;
  background-color: #f5f5f5;
}

/* 控制设置标题 */
.control-title {
  font-size: 32rpx;
  font-weight: 500;
  text-align: center;
  margin-bottom: 30rpx;
  color: #333;
}

/* 2列栅格布局 */
.card-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20rpx;
  padding: 20rpx;
}

/* 卡片样式 */
.control-card {
  background-color: #fff;
  border-radius: 16rpx;
  padding: 30rpx 20rpx;
  display: flex;
  justify-content: space-between;
  align-items: center;
  box-shadow: 0 2rpx 8rpx #bfbec1;
}

/* 卡片文字区域 */
.card-text {
  display: flex;
  flex-direction: column;
  gap: 8rpx;
}

.card-main {
  font-size: 30rpx;
  color: #333;
  font-weight: 500;
}

.card-sub {
  font-size: 24rpx;
  color: #999;
}

/* 卡片图标容器 */
.card-icon {
  width: 48rpx;
  height: 48rpx;
  border-radius: 50%;
  background-color: #e5e5e5;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* 激活状态（运行） */
.card-icon.active {
  background-color: #007aff;
}
.uni-px-5 {
  padding-left: 20rpx;
  padding-right: 20rpx;
}

.uni-pb-5 {
  padding-bottom: 40rpx;
}

.text {
  width: 50rpx;
  margin: 10rpx 10rpx 8rpx 0;
  padding: 0;
  height: 70rpx;
  line-height: 70rpx;
  text-align: center;
  font-size: 26rpx;
  box-shadow: 0 2rpx 8rpx #bfbec1
}

.tempStyle,.humiStyle {
  display: inline-block;
  font-size: 12px;
}

.text:first-child {
  margin-left: 10rpx;
}

.uni-view {
  -webkit-flex: 1;
  flex: 1;
  height: 150rpx;
  -webkit-justify-content: center;
  justify-content: center;
  -webkit-align-items: center;
  align-items: center;
}

.data {
  font-size: 13px;
  display: inline-block;
  line-height: 23px;
  color: #3a3a3a;
}
.data:nth-child(even) {
  font-size: 12px;
  margin-top: 3px;
  color: #9c9c9c;
}
/deep/ .uni-section-header__slot-right {
  color: green;
}
</style>
