<template>
  <div class="pcs-ems-dashboard-editor-container">
    <div class="pcs-tags">
      <el-tag
          size="small"
          :type="selectedPcsId ? 'info' : 'primary'"
          :effect="selectedPcsId ? 'plain' : 'dark'"
          class="pcs-tag-item"
          @click="handleTagClick('')"
      >
        全部
      </el-tag>
      <el-tag
          v-for="(item, index) in pcsDeviceList"
          :key="index + 'pcsTag'"
          size="small"
          :type="selectedPcsId === (item.deviceId || item.id) ? 'primary' : 'info'"
          :effect="selectedPcsId === (item.deviceId || item.id) ? 'dark' : 'plain'"
          class="pcs-tag-item"
          @click="handleTagClick(item.deviceId || item.id || '')"
      >
        {{ item.deviceName || item.deviceId || item.id || 'PCS' }}
      </el-tag>
    </div>
    <div
        v-for="(pcsItem, pcsIndex) in filteredPcsList"
        :key="pcsIndex + 'PcsHome'"
        style="margin-bottom: 25px"
    >
      <el-card
          :class="handleCardClass(pcsItem)"
          class="sbjk-card-container common-card-container-body-no-padding common-card-container-no-title-bg"
          shadow="always"
      >
        <div slot="header">
          <span class="large-title"
          >{{ pcsItem.deviceName }}</span
          >
          <div class="info">
            <div v-if="(($store.state.ems && $store.state.ems.communicationStatusOptions) || {})[pcsItem.communicationStatus]">
              {{ (($store.state.ems && $store.state.ems.communicationStatusOptions) || {})[pcsItem.communicationStatus] }}
            </div>
            <div>数据更新时间：{{ pcsItem.dataUpdateTime }}</div>
          </div>
          <div class="alarm">
            <el-badge :hidden="!pcsItem.alarmNum" :value="pcsItem.alarmNum || 0" class="item">
              <i
                  class="el-icon-message-solid alarm-icon"
                  @click="pointDetail(pcsItem,'alarmPoint')"
              ></i>
            </el-badge>
          </div>
        </div>
        <div class="descriptions-main">
          <el-descriptions :colon="false" :column="4" direction="vertical">
            <el-descriptions-item
                contentClassName="descriptions-direction work-status"
                :span="1"
                label="工作状态"
                labelClassName="descriptions-label"
            >
              <span
                class="pointer"
                :class="{ 'field-disabled': !hasFieldPointId(pcsItem, 'workStatus') }"
                @click="handlePcsFieldClick(pcsItem, 'workStatus', '工作状态')"
              >
                {{ formatDictValue((PCSWorkStatusOptions || {}), pcsItem.workStatus) }}
              </span>
            </el-descriptions-item
            >
            <el-descriptions-item
                :span="1"
                contentClassName="descriptions-direction"
                label="并网状态"
                labelClassName="descriptions-label"
            >
              <span
                class="pointer"
                :class="{ 'field-disabled': !hasFieldPointId(pcsItem, 'gridStatus') }"
                @click="handlePcsFieldClick(pcsItem, 'gridStatus', '并网状态')"
              >
                {{ formatDictValue((($store.state.ems && $store.state.ems.gridStatusOptions) || {}), pcsItem.gridStatus) }}
              </span>
            </el-descriptions-item
            >
            <el-descriptions-item
                :contentClassName="`descriptions-direction ${
                pcsItem.deviceStatus === '1' ? 'save' : 'danger'
              }`"
                :span="1"
                label="设备状态"
                labelClassName="descriptions-label"
            >
              <span
                class="pointer"
                :class="{ 'field-disabled': !hasFieldPointId(pcsItem, 'deviceStatus') }"
                @click="handlePcsFieldClick(pcsItem, 'deviceStatus', '设备状态')"
              >
                {{ formatDictValue((($store.state.ems && $store.state.ems.deviceStatusOptions) || {}), pcsItem.deviceStatus) }}
              </span>
            </el-descriptions-item
            >
            <el-descriptions-item
                :span="1"
                contentClassName="descriptions-direction"
                label="控制模式"
                labelClassName="descriptions-label"
            >
              <span
                class="pointer"
                :class="{ 'field-disabled': !hasFieldPointId(pcsItem, 'controlMode') }"
                @click="handlePcsFieldClick(pcsItem, 'controlMode', '控制模式')"
              >
                {{ formatDictValue((($store.state.ems && $store.state.ems.controlModeOptions) || {}), pcsItem.controlMode) }}
              </span>
            </el-descriptions-item
            >
          </el-descriptions>
        </div>
        <div class="descriptions-main descriptions-main-bg-color">
          <el-descriptions
              :colon="false"
              :column="4"
              contentClassName="descriptions-direction"
              direction="vertical"
              labelClassName="descriptions-label"
          >
            <el-descriptions-item
                v-for="(item, index) in infoData"
                :key="index + 'pcsInfoData'"
                :label="item.label"
                :span="1"
            >
              <span
                  class="pointer"
                  :class="{ 'field-disabled': !hasFieldPointId(pcsItem, item.attr) }"
                  @click="handlePcsFieldClick(pcsItem, item.attr, item.label)"
              >
                <i v-if="isPointLoading(pcsItem[item.attr])" class="el-icon-loading point-loading-icon"></i>
                <span v-else>{{ displayValue(pcsItem[item.attr]) | formatNumber }}</span>
                <span v-if="item.unit" v-html="item.unit"></span>
              </span>
            </el-descriptions-item>
          </el-descriptions>
        </div>
        <div
            v-for="(item, index) in pcsItem.pcsBranchInfoList"
            :key="index + 'pcsBranchInfoList'"
            class="descriptions-main"
        >
          <el-descriptions
              :colon="false"
              :column="4"
              contentClassName="descriptions-direction keep"
              direction="vertical"
              labelClassName="descriptions-label"
          >
            <el-descriptions-item
                :label="'支路' + (index + 1)"
                :span="4"
                contentClassName="descriptions-direction keep"
                labelClassName="descriptions-label"
            >{{ item.dischargeStatus }}
            </el-descriptions-item
            >
            <el-descriptions-item
                :span="1"
                contentClassName="descriptions-direction"
                label="直流功率"
                labelClassName="descriptions-label"
            >
              <span
                  class="pointer"
                  :class="{ 'field-disabled': !item.dcPowerPointId }"
                  @click="openCurveDialogByPointId(item.dcPowerPointId, '直流功率')"
              >{{ item.dcPower }}kW</span
              >
            </el-descriptions-item>
            <el-descriptions-item
                :span="1"
                contentClassName="descriptions-direction"
                label="直流电压"
                labelClassName="descriptions-label"
            >
              <span
                  class="pointer"
                  :class="{ 'field-disabled': !item.dcVoltagePointId }"
                  @click="openCurveDialogByPointId(item.dcVoltagePointId, '直流电压')"
              >{{ item.dcVoltage }}V</span
              >
            </el-descriptions-item>
            <el-descriptions-item
                :span="1"
                contentClassName="descriptions-direction"
                label="直流电流"
                labelClassName="descriptions-label"
            >
              <span
                  class="pointer"
                  :class="{ 'field-disabled': !item.dcCurrentPointId }"
                  @click="openCurveDialogByPointId(item.dcCurrentPointId, '直流电流')"
              >{{ item.dcCurrent }}A</span
              >
            </el-descriptions-item>
          </el-descriptions>
        </div>
      </el-card>
    </div>
    <point-table ref="pointTable"/>
    <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 PointTable from "@/views/ems/site/sblb/PointTable.vue";
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import {getPcsNameList, getProjectDisplayData} from "@/api/ems/dzjk";
import intervalUpdate from "@/mixins/ems/intervalUpdate";
import {mapState} from "vuex";
import {getPointConfigCurve} from "@/api/ems/site";

export default {
  name: "DzjkSbjkPcs",
  components: {PointTable},
  mixins: [getQuerySiteId, intervalUpdate],
  computed: {
    ...mapState({
      PCSWorkStatusOptions: state => state?.ems?.PCSWorkStatusOptions || {},
    }),
    filteredPcsList() {
      if (!this.selectedPcsId) {
        return this.pcsList || [];
      }
      return (this.pcsList || []).filter(item => item.deviceId === this.selectedPcsId);
    },
  },
  data() {
    return {
      loading: false,
      displayData: [],
      pcsDeviceList: [],
      selectedPcsId: "",
      curveDialogVisible: false,
      curveDialogTitle: "点位曲线",
      curveChart: null,
      curveLoading: false,
      curveCustomRange: [],
      curveQuery: {
        siteId: "",
        pointId: "",
        pointType: "data",
        rangeType: "custom",
        startTime: "",
        endTime: "",
      },
      pcsList: [{
        deviceId: "",
        deviceName: "PCS",
        dataUpdateTime: "-",
        alarmNum: 0,
        pcsBranchInfoList: [],
      }],
      infoData: [
        {
          label: "总交流有功功率",
          attr: "totalActivePower",
          unit: "kW",
          pointName: "总交流有功功率",
        },
        {
          label: "当天交流充电量",
          attr: "dailyAcChargeEnergy",
          unit: "kWh",
          pointName: "当天交流充电量 (kWh)",
        },
        {label: "A相电压", attr: "aPhaseVoltage", unit: "V", pointName: ""},
        {
          label: "A相电流",
          attr: "aPhaseCurrent",
          unit: "A",
          pointName: "A相电流",
        },
        {
          label: "总交流无功功率",
          attr: "totalReactivePower",
          unit: "kVar",
          pointName: "总交流无功功率",
        },
        {
          label: "当天交流放电量",
          attr: "dailyAcDischargeEnergy",
          unit: "kWh",
          pointName: "当天交流放电量 (kWh)",
        },
        {label: "B相电压", attr: "bPhaseVoltage", unit: "V", pointName: ""},
        {
          label: "B相电流",
          attr: "bPhaseCurrent",
          unit: "A",
          pointName: "B相电流",
        },
        {
          label: "总交流视在功率",
          attr: "totalApparentPower",
          unit: "kVA",
          pointName: "总交流视在功率",
        },
        {
          label: "PCS模块温度",
          attr: "pcsModuleTemperature",
          unit: "&#8451;",
          pointName: "",
        },
        {label: "C相电压", attr: "cPhaseVoltage", unit: "V", pointName: ""},
        {
          label: "C相电流",
          attr: "cPhaseCurrent",
          unit: "A",
          pointName: "C相电流",
        },
        {
          label: "总交流功率因数",
          attr: "totalPowerFactor",
          unit: "",
          pointName: "总交流功率因数",
        },
        {
          label: "PCS环境温度",
          attr: "pcsEnvironmentTemperature",
          unit: "&#8451;",
          pointName: "",
        },
        {
          label: "交流频率",
          attr: "acFrequency",
          unit: "Hz",
          pointName: "交流频率",
        },
      ],
    };
  },
  methods: {
    displayValue(value) {
      return value === undefined || value === null || value === "" ? "-" : value;
    },
    isPointLoading(value) {
      return this.loading && (value === undefined || value === null || value === "" || value === "-");
    },
    normalizeDictKey(value) {
      const raw = String(value == null ? "" : value).trim();
      if (!raw) return "";
      if (/^-?\d+(\.0+)?$/.test(raw)) {
        return String(parseInt(raw, 10));
      }
      return raw;
    },
    formatDictValue(options, value) {
      const dict = (options && typeof options === "object") ? options : {};
      const key = this.normalizeDictKey(value);
      if (!key) return "-";
      return dict[key] || key;
    },
    normalizeDeviceId(value) {
      return String(value == null ? "" : value).trim().toUpperCase();
    },
    handleCardClass(item) {
      const workStatus = this.normalizeDictKey((item && item.workStatus) || "");
      const statusOptions = (this.PCSWorkStatusOptions && typeof this.PCSWorkStatusOptions === 'object')
        ? this.PCSWorkStatusOptions
        : {};
      const hasStatus = Object.prototype.hasOwnProperty.call(statusOptions, workStatus);
      return workStatus === '1' || !hasStatus
        ? "timing-card-container"
        : workStatus === '2'
          ? 'warning-card-container'
          : 'running-card-container';
    },
    // 查看设备电位表格
    pointDetail(row, dataType) {
      const {deviceId} = row
      this.$refs.pointTable.showTable({siteId: this.siteId, deviceId, deviceCategory: 'PCS'}, dataType)
    },
    hasFieldPointId(pcsItem, fieldName) {
      const row = this.getFieldRow(pcsItem, fieldName);
      return !!String(row?.dataPoint || "").trim();
    },
    getFieldRow(pcsItem, fieldName) {
      const key = String(fieldName || "").trim();
      const map = pcsItem?._fieldRowMap || {};
      return map[key] || null;
    },
    handlePcsFieldClick(pcsItem, fieldName, title) {
      const row = this.getFieldRow(pcsItem, fieldName);
      const pointId = String(row?.dataPoint || "").trim();
      this.openCurveDialogByPointId(pointId, title || fieldName);
    },
    openCurveDialogByPointId(pointId, title) {
      const normalizedPointId = String(pointId || "").trim();
      if (!normalizedPointId) {
        this.$message.warning("该字段未配置点位，无法查询曲线");
        return;
      }
      const range = this.getDefaultCurveRange();
      this.curveCustomRange = range;
      this.curveDialogTitle = `点位曲线 - ${title || normalizedPointId}`;
      this.curveQuery = {
        siteId: this.siteId,
        pointId: normalizedPointId,
        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(deviceId) {
      this.selectedPcsId = deviceId || "";
    },
    getModuleRows(menuCode, sectionName) {
      return (this.displayData || []).filter(item => item.menuCode === menuCode && item.sectionName === sectionName);
    },
    getFieldName(fieldCode) {
      if (!fieldCode) {
        return "";
      }
      const index = fieldCode.lastIndexOf("__");
      return index >= 0 ? fieldCode.slice(index + 2) : fieldCode;
    },
    getFieldMap(rows = [], deviceId = "") {
      const rowMap = this.getFieldRowMap(rows, deviceId);
      return Object.keys(rowMap).reduce((acc, fieldName) => {
        const row = rowMap[fieldName] || {};
        acc[fieldName] = row.fieldValue;
        return acc;
      }, {});
    },
    getFieldRowMap(rows = [], deviceId = "") {
      const map = {};
      const targetDeviceId = this.normalizeDeviceId(deviceId || "");
      // 设备维度优先：先吃 device_id 对应值，再用默认值(空 device_id)补齐
      rows.forEach(item => {
        if (!item || !item.fieldCode) {
          return;
        }
        const itemDeviceId = this.normalizeDeviceId(item.deviceId || "");
        if (itemDeviceId !== targetDeviceId) {
          return;
        }
        map[this.getFieldName(item.fieldCode)] = item;
      });
      rows.forEach(item => {
        if (!item || !item.fieldCode) {
          return;
        }
        const itemDeviceId = this.normalizeDeviceId(item.deviceId || "");
        if (itemDeviceId !== "") {
          return;
        }
        const fieldName = this.getFieldName(item.fieldCode);
        if (map[fieldName] === undefined || map[fieldName] === null || map[fieldName] === "") {
          map[fieldName] = item;
        }
      });
      return map;
    },
    getLatestTime(menuCode) {
      const times = (this.displayData || [])
        .filter(item => item.menuCode === menuCode && item.valueTime)
        .map(item => new Date(item.valueTime).getTime())
        .filter(ts => !isNaN(ts));
      if (times.length === 0) {
        return '-';
      }
      const date = new Date(Math.max(...times));
      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())}`;
    },
    getPcsDeviceList() {
      return getPcsNameList(this.siteId).then((response) => {
        this.pcsDeviceList = response?.data || [];
      }).catch(() => {
        this.pcsDeviceList = [];
      });
    },
    buildPcsList() {
      const devices = (this.pcsDeviceList && this.pcsDeviceList.length > 0)
        ? this.pcsDeviceList
        : [{deviceId: this.siteId, deviceName: 'PCS'}];
      this.pcsList = devices.map((device) => ({
        ...this.getFieldMap(this.getModuleRows('SBJK_PCS', '电参量'), device.deviceId || device.id || this.siteId),
        deviceId: device.deviceId || device.id || this.siteId,
        deviceName: device.deviceName || device.name || device.deviceId || device.id || 'PCS',
        ...this.getFieldMap(this.getModuleRows('SBJK_PCS', '状态'), device.deviceId || device.id || this.siteId),
        _fieldRowMap: {
          ...this.getFieldRowMap(this.getModuleRows('SBJK_PCS', '电参量'), device.deviceId || device.id || this.siteId),
          ...this.getFieldRowMap(this.getModuleRows('SBJK_PCS', '状态'), device.deviceId || device.id || this.siteId),
        },
        dataUpdateTime: this.getLatestTime('SBJK_PCS'),
        alarmNum: 0,
        pcsBranchInfoList: [],
      }));
    },
    updateData() {
      this.loading = true;
      // 先渲染卡片框架，字段值走单点位 loading
      this.buildPcsList();
      Promise.all([
        getProjectDisplayData(this.siteId),
        this.getPcsDeviceList(),
      ]).then(([displayResponse]) => {
        this.displayData = displayResponse?.data || [];
        this.buildPcsList();
      }).finally(() => (this.loading = false));
    },
    init() {
      this.updateData();
      this.updateInterval(this.updateData);
    },
  },
  beforeDestroy() {
    if (this.curveChart) {
      this.curveChart.dispose();
      this.curveChart = null;
    }
  },
};
</script>
<style lang="scss" scoped>
.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;
}

.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>
