<template>
  <div>
    <div class="pcs-tags">
      <el-tag
        size="small"
        :type="selectedSectionKey ? 'info' : 'primary'"
        :effect="selectedSectionKey ? 'plain' : 'dark'"
        class="pcs-tag-item"
        @click="handleTagClick('')"
      >
        全部
      </el-tag>
      <el-tag
        v-for="(group, index) in sectionGroups"
        :key="index + 'dbTag'"
        size="small"
        :type="selectedSectionKey === group.sectionKey ? 'primary' : 'info'"
        :effect="selectedSectionKey === group.sectionKey ? 'dark' : 'plain'"
        class="pcs-tag-item"
        @click="handleTagClick(group.sectionKey)"
      >
        {{ group.displayName || "电表" }}
      </el-tag>
    </div>
    <el-card
      v-for="(group, index) in filteredSectionGroups"
      :key="index + 'dbSection'"
      class="sbjk-card-container list running-card-container"
      shadow="always"
    >
      <div slot="header">
        <span class="large-title">{{ group.displayName || "电表" }}</span>
        <div class="info">
          <div>状态：{{ group.statusText }}</div>
          <div>数据更新时间：{{ group.updateTimeText }}</div>
        </div>
      </div>
      <el-row class="device-info-row">
        <el-col
          v-for="(item, dataIndex) in group.items"
          :key="dataIndex + 'dbField'"
          :span="8"
          class="device-info-col"
          :class="{ 'field-disabled': !item.pointId }"
        >
          <div class="field-click-wrapper" @click="handleFieldClick(item)">
            <span class="left">{{ item.fieldName }}</span>
            <span class="right">
              <i v-if="isPointLoading(item.fieldValue)" class="el-icon-loading point-loading-icon"></i>
              <span v-else>{{ displayValue(item.fieldValue) | formatNumber }}</span>
            </span>
          </div>
        </el-col>
      </el-row>
    </el-card>

    <el-dialog
      :visible.sync="curveDialogVisible"
      :title="curveDialogTitle"
      width="1000px"
      append-to-body
      class="ems-dialog"
      :close-on-click-modal="false"
      destroy-on-close
      @opened="handleCurveDialogOpened"
      @closed="handleCurveDialogClosed"
    >
      <div class="curve-tools">
        <el-date-picker
          v-model="curveCustomRange"
          type="datetimerange"
          value-format="yyyy-MM-dd HH:mm:ss"
          range-separator="至"
          start-placeholder="开始时间"
          end-placeholder="结束时间"
          style="width: 440px"
        />
        <el-button type="primary" size="mini" :loading="curveLoading" @click="loadCurveData">查询</el-button>
      </div>
      <div v-loading="curveLoading" ref="curveChartRef" style="height: 380px;"></div>
    </el-dialog>
  </div>
</template>

<script>
import * as echarts from "echarts";
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import intervalUpdate from "@/mixins/ems/intervalUpdate";
import { getProjectDisplayData } from "@/api/ems/dzjk";
import { getDeviceList, getPointConfigCurve } from "@/api/ems/site";

export default {
  name: "DzjkSbjkDb",
  mixins: [getQuerySiteId, intervalUpdate],
  data() {
    return {
      loading: false,
      displayData: [],
      selectedSectionKey: "",
      ammeterDeviceList: [],
      curveDialogVisible: false,
      curveDialogTitle: "点位曲线",
      curveChart: null,
      curveLoading: false,
      curveCustomRange: [],
      curveQuery: {
        siteId: "",
        pointId: "",
        pointType: "data",
        rangeType: "custom",
        startTime: "",
        endTime: "",
      },
    };
  },
  computed: {
    moduleDisplayData() {
      return (this.displayData || []).filter((item) => item.menuCode === "SBJK_DB");
    },
    dbTemplateFields() {
      const source = this.moduleDisplayData || [];
      const result = [];
      const seen = new Set();
      source.forEach((item) => {
        const fieldName = String(item?.fieldName || "").trim();
        if (!fieldName || seen.has(fieldName)) {
          return;
        }
        seen.add(fieldName);
        result.push(fieldName);
      });
      return result.length > 0 ? result : this.fallbackFields;
    },
    sectionGroups() {
      const source = this.moduleDisplayData || [];
      const devices = (this.ammeterDeviceList || []).length > 0
        ? this.ammeterDeviceList
        : [{ deviceId: "", deviceName: "电表" }];

      return devices.map((device, index) => {
        const deviceId = String(device?.deviceId || device?.id || "").trim();
        const sectionKey = deviceId || `AMMETER_${index}`;
        const displayName = String(device?.deviceName || device?.name || deviceId || `电表${index + 1}`).trim();
        const exactRows = source.filter((item) => String(item?.deviceId || "").trim() === deviceId);
        const fallbackRows = source.filter((item) => !String(item?.deviceId || "").trim());

        const exactValueMap = {};
        exactRows.forEach((item) => {
          const key = String(item?.fieldName || "").trim();
          if (key) {
            exactValueMap[key] = item;
          }
        });
        const fallbackValueMap = {};
        fallbackRows.forEach((item) => {
          const key = String(item?.fieldName || "").trim();
          if (key && fallbackValueMap[key] === undefined) {
            fallbackValueMap[key] = item;
          }
        });

        const items = (this.dbTemplateFields || []).map((fieldName) => {
          const row = exactValueMap[fieldName] || fallbackValueMap[fieldName] || {};
          return {
            fieldName,
            fieldValue: row.fieldValue,
            valueTime: row.valueTime,
            pointId: String(row?.dataPoint || "").trim(),
            raw: row,
          };
        });

        const statusItem = (items || []).find((it) => String(it.fieldName || "").includes("状态"));
        const timestamps = [...exactRows, ...fallbackRows]
          .map((it) => new Date(it?.valueTime).getTime())
          .filter((ts) => !isNaN(ts));

        return {
          sectionName: displayName,
          sectionKey,
          displayName,
          deviceId,
          items,
          statusText: this.displayValue(statusItem ? statusItem.fieldValue : "-"),
          updateTimeText: timestamps.length > 0 ? this.formatDate(new Date(Math.max(...timestamps))) : "-",
        };
      });
    },
    displaySectionGroups() {
      if (this.sectionGroups.length > 0) {
        return this.sectionGroups;
      }
      return [
        {
          sectionName: "电参量",
          sectionKey: "电参量",
          displayName: "电表",
          items: this.fallbackFields.map((fieldName) => ({ fieldName, fieldValue: "-" })),
          statusText: "-",
          updateTimeText: "-",
        },
      ];
    },
    filteredSectionGroups() {
      const groups = this.displaySectionGroups || [];
      if (!this.selectedSectionKey) {
        return groups;
      }
      return groups.filter((group) => group.sectionKey === this.selectedSectionKey);
    },
    fallbackFields() {
      return [
        "正向有功电能",
        "反向有功电能",
        "正向无功电能",
        "反向无功电能",
        "有功功率",
        "无功功率",
      ];
    },
  },
  methods: {
    handleFieldClick(item) {
      const pointId = String(item?.pointId || item?.raw?.dataPoint || "").trim();
      if (!pointId) {
        this.$message.warning("该字段未配置点位，无法查询曲线");
        return;
      }
      this.openCurveDialog({
        pointId,
        title: item?.fieldName || pointId,
      });
    },
    openCurveDialog({ pointId, title }) {
      const range = this.getDefaultCurveRange();
      this.curveCustomRange = range;
      this.curveDialogTitle = `点位曲线 - ${title || pointId}`;
      this.curveQuery = {
        siteId: this.siteId,
        pointId,
        pointType: "data",
        rangeType: "custom",
        startTime: range[0],
        endTime: range[1],
      };
      this.curveDialogVisible = true;
    },
    handleCurveDialogOpened() {
      if (!this.curveChart && this.$refs.curveChartRef) {
        this.curveChart = echarts.init(this.$refs.curveChartRef);
      }
      this.loadCurveData();
    },
    handleCurveDialogClosed() {
      if (this.curveChart) {
        this.curveChart.dispose();
        this.curveChart = null;
      }
      this.curveLoading = false;
    },
    getDefaultCurveRange() {
      const end = new Date();
      const start = new Date(end.getTime() - 24 * 60 * 60 * 1000);
      return [this.formatDateTime(start), this.formatDateTime(end)];
    },
    formatDateTime(date) {
      const d = new Date(date);
      const p = (n) => String(n).padStart(2, "0");
      return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
    },
    formatCurveTime(value) {
      if (value === undefined || value === null || value === "") {
        return "";
      }
      const raw = String(value).trim();
      const normalized = raw
        .replace("T", " ")
        .replace(/\.\d+/, "")
        .replace(/Z$/, "")
        .replace(/([+-]\d{2}:?\d{2})$/, "")
        .trim();
      const matched = normalized.match(/^(\d{4}-\d{2}-\d{2})\s+(\d{2}:\d{2})/);
      if (matched) {
        return `${matched[1]} ${matched[2]}`;
      }
      return normalized.slice(0, 16);
    },
    loadCurveData() {
      if (!this.curveQuery.siteId || !this.curveQuery.pointId) {
        this.$message.warning("点位信息不完整，无法查询曲线");
        return;
      }
      if (!this.curveCustomRange || this.curveCustomRange.length !== 2) {
        this.$message.warning("请选择查询时间范围");
        return;
      }
      this.curveQuery.startTime = this.curveCustomRange[0];
      this.curveQuery.endTime = this.curveCustomRange[1];
      const query = {
        siteId: this.curveQuery.siteId,
        pointId: this.curveQuery.pointId,
        pointType: "data",
        rangeType: "custom",
        startTime: this.curveQuery.startTime,
        endTime: this.curveQuery.endTime,
      };
      this.curveLoading = true;
      getPointConfigCurve(query)
        .then((response) => {
          const rows = response?.data || [];
          this.renderCurveChart(rows);
        })
        .catch(() => {
          this.renderCurveChart([]);
        })
        .finally(() => {
          this.curveLoading = false;
        });
    },
    renderCurveChart(rows = []) {
      if (!this.curveChart) return;
      const xData = rows.map((item) => this.formatCurveTime(item.dataTime));
      const yData = rows.map((item) => item.pointValue);
      this.curveChart.clear();
      this.curveChart.setOption({
        legend: {},
        grid: {
          containLabel: true,
        },
        tooltip: {
          trigger: "axis",
          axisPointer: {
            type: "cross",
          },
        },
        textStyle: {
          color: "#333333",
        },
        xAxis: {
          type: "category",
          data: xData,
        },
        yAxis: {
          type: "value",
        },
        dataZoom: [
          {
            type: "inside",
            start: 0,
            end: 100,
          },
          {
            start: 0,
            end: 100,
          },
        ],
        series: [
          {
            name: this.curveDialogTitle,
            type: "line",
            data: yData,
            connectNulls: true,
          },
        ],
      });
      if (!rows.length) {
        this.$message.warning("当前时间范围暂无曲线数据");
      }
    },
    handleTagClick(sectionKey) {
      this.selectedSectionKey = sectionKey || "";
    },
    displayValue(value) {
      return value === undefined || value === null || value === "" ? "-" : value;
    },
    isPointLoading(value) {
      return this.loading && (value === undefined || value === null || value === "" || value === "-");
    },
    formatDate(date) {
      if (!(date instanceof Date) || isNaN(date.getTime())) {
        return "-";
      }
      const p = (n) => String(n).padStart(2, "0");
      return `${date.getFullYear()}-${p(date.getMonth() + 1)}-${p(date.getDate())} ${p(date.getHours())}:${p(
        date.getMinutes()
      )}:${p(date.getSeconds())}`;
    },
    resolveDbDisplayName(sectionName) {
      const key = String(sectionName || "").trim();
      if (!key) {
        return "电表";
      }
      const list = this.ammeterDeviceList || [];
      const matched = list.find((item) => {
        const deviceId = String(item.deviceId || item.id || "").trim();
        const deviceName = String(item.deviceName || item.name || "").trim();
        return key === deviceId || key === deviceName;
      });
      if (matched) {
        return matched.deviceName || matched.name || key;
      }
      return key;
    },
    getAmmeterDeviceList() {
      return getDeviceList(this.siteId)
        .then((response) => {
          const list = response?.data || [];
          this.ammeterDeviceList = list.filter((item) => item.deviceCategory === "AMMETER");
        })
        .catch(() => {
          this.ammeterDeviceList = [];
        });
    },
    updateData() {
      this.loading = true;
      Promise.all([getProjectDisplayData(this.siteId), this.getAmmeterDeviceList()])
        .then(([response]) => {
          this.displayData = response?.data || [];
        })
        .finally(() => {
          this.loading = false;
        });
    },
    init() {
      this.updateData();
      this.updateInterval(this.updateData);
    },
  },
  beforeDestroy() {
    if (this.curveChart) {
      this.curveChart.dispose();
      this.curveChart = null;
    }
  },
};
</script>

<style scoped lang="scss">
.sbjk-card-container {
  &.list:not(:last-child) {
    margin-bottom: 25px;
  }

  .info {
    float: right;
    text-align: right;
    font-size: 12px;
    color: #666;
    line-height: 18px;
  }
}

.pcs-tags {
  margin: 0 0 12px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: flex-start;
  align-items: center;
}

.pcs-tag-item {
  cursor: pointer;
}

.device-info-col {
  cursor: pointer;
}

.field-click-wrapper {
  width: 100%;
}

.device-info-col.field-disabled {
  cursor: not-allowed;
  opacity: 0.8;
}

.curve-tools {
  margin-bottom: 10px;
  display: flex;
  align-items: center;
  gap: 10px;
}

.point-loading-icon {
  color: #409eff;
  display: inline-block;
  transform-origin: center;
  animation: pointLoadingSpinPulse 1.1s linear infinite;
}
@keyframes pointLoadingSpinPulse {
  0% { opacity: 0.45; transform: rotate(0deg) scale(0.9); }
  50% { opacity: 1; transform: rotate(180deg) scale(1.08); }
  100% { opacity: 0.45; transform: rotate(360deg) scale(0.9); }
}
</style>
