<template>
  <el-dialog
    v-loading="loading"
    width="92%"
    :visible.sync="dialogTableVisible"
    class="ems-dialog plan-dialog"
    title="保护方案"
    :close-on-click-modal="false"
    :show-close="false"
  >
    <el-form
      v-loading="loading > 0"
      ref="addTempForm"
      :model="formData"
      :rules="rules"
      size="medium"
      label-width="120px"
      class="plan-form"
    >
      <div class="base-panel">
        <div class="panel-title">基础信息</div>
        <div class="base-grid">
          <el-form-item label="设备保护名称" prop="faultName" class="span-1">
            <el-input v-model="formData.faultName" placeholder="请输入" clearable></el-input>
          </el-form-item>
          <el-form-item label="是否告警" prop="isAlert" class="span-1">
            <el-checkbox v-model="formData.isAlert" :true-label="1" :false-label="0">启用告警</el-checkbox>
          </el-form-item>
          <el-form-item label="告警等级" prop="faultLevel" class="span-1">
            <el-radio-group v-model="formData.faultLevel" :disabled="mode === 'edit'">
              <el-radio :label="1">等级1</el-radio>
              <el-radio :label="2">等级2</el-radio>
              <el-radio :label="3">等级3</el-radio>
            </el-radio-group>
          </el-form-item>
          <el-form-item label="处理方案描述" prop="description" class="span-2">
            <el-input
              v-model="formData.description"
              type="textarea"
              :rows="2"
              placeholder="请输入"
              clearable
            ></el-input>
          </el-form-item>
        </div>
      </div>

      <div class="plan-section">
        <div class="section-head">
          <div>
            <div class="section-title">保护前提</div>
            <div class="section-desc">配置触发故障的判定条件和关系</div>
          </div>
          <div class="section-actions">
            <el-button @click.native.prevent="addRow('protectionSettings')" type="primary" size="mini">
              新增保护前提
            </el-button>
          </div>
        </div>

        <div class="row-card" v-for="(item, index) in protectionSettings" :key="'protectionSettings' + index">
          <div class="row-index">{{ index + 1 }}</div>
          <div class="row-grid setting-grid">
            <div class="field-block field-point">
              <div class="field-label">点位</div>
              <el-autocomplete
                v-model="item.point"
                placeholder="请输入点位ID/描述"
                clearable
                :trigger-on-focus="false"
                :debounce="250"
                :value-key="'label'"
                :fetch-suggestions="(q, c) => querySearchAsync(q, c, index, 'protectionSettings')"
                @select="(v) => handleSelect(v, index, 'protectionSettings')"
                @blur="() => fillPointMetaByPoint(item.point, index, 'protectionSettings')"
              ></el-autocomplete>
            </div>

            <div class="field-block">
              <div class="field-label">故障比较符</div>
              <el-select v-model="item.faultOperator" placeholder="请选择">
                <el-option
                  v-for="(value, key) in comparisonOperatorOptions"
                  :key="key + 'faultOperator'"
                  :label="key"
                  :value="value"
                ></el-option>
              </el-select>
            </div>

            <div class="field-block">
              <div class="field-label">故障值</div>
              <el-input placeholder="请输入故障值" v-model="item.faultValue"></el-input>
            </div>

            <div class="field-block">
              <div class="field-label">释放比较符</div>
              <el-select v-model="item.releaseOperator" placeholder="请选择">
                <el-option
                  v-for="(value, key) in comparisonOperatorOptions"
                  :key="key + 'releaseOperator'"
                  :label="key"
                  :value="value"
                ></el-option>
              </el-select>
            </div>

            <div class="field-block">
              <div class="field-label">释放值</div>
              <el-input placeholder="请输入释放值" v-model="item.releaseValue"></el-input>
            </div>

            <div class="field-block">
              <div class="field-label">关系</div>
              <el-select v-model="item.relationNext" placeholder="请选择">
                <el-option
                  v-for="(value, key) in relationWithPoint"
                  :key="key + 'relation'"
                  :label="key"
                  :value="value"
                ></el-option>
              </el-select>
            </div>
          </div>
          <div class="row-action">
            <el-button @click.native.prevent="deleteRow(index, 'protectionSettings')" type="warning" size="mini">
              删除
            </el-button>
          </div>
        </div>

        <el-empty v-if="protectionSettings.length === 0" description="暂无保护前提，请先添加"></el-empty>
      </div>

      <div class="plan-section">
        <div class="section-head">
          <div>
            <div class="section-title">保护方案</div>
            <div class="section-desc">设置触发后的目标写入点位和值</div>
          </div>
          <div class="section-actions">
            <el-button @click.native.prevent="addRow('protectionPlan')" type="primary" size="mini">
              新增保护方案
            </el-button>
          </div>
        </div>

        <div class="row-card" v-for="(item, index) in protectionPlan" :key="'protectionPlan' + index">
          <div class="row-index">{{ index + 1 }}</div>
          <div class="row-grid plan-grid">
            <div class="field-block field-point">
              <div class="field-label">点位</div>
              <el-autocomplete
                v-model="item.point"
                placeholder="请输入点位ID/描述"
                clearable
                :trigger-on-focus="false"
                :debounce="250"
                :value-key="'label'"
                :fetch-suggestions="(q, c) => querySearchAsync(q, c, index, 'protectionPlan')"
                @select="(v) => handleSelect(v, index, 'protectionPlan')"
                @blur="() => fillPointMetaByPoint(item.point, index, 'protectionPlan')"
              ></el-autocomplete>
            </div>

            <div class="field-block eq-block">
              <div class="field-label">比较</div>
              <div class="eq-text">=</div>
            </div>

            <div class="field-block">
              <div class="field-label">故障值</div>
              <el-input placeholder="请输入故障值" v-model="item.value"></el-input>
            </div>
          </div>
          <div class="row-action">
            <el-button @click.native.prevent="deleteRow(index, 'protectionPlan')" type="warning" size="mini">
              删除
            </el-button>
          </div>
        </div>

        <el-empty v-if="protectionPlan.length === 0" description="暂无保护方案，请先添加"></el-empty>
      </div>
    </el-form>

    <div slot="footer" class="dialog-footer">
      <el-button @click="closeDialog">取消</el-button>
      <el-button type="primary" @click="saveDialog">确定</el-button>
    </div>
  </el-dialog>
</template>

<script>
import { mapState } from "vuex";
import { validText } from "@/utils/validate";
import { addProtectPlan, getPointMatchList, getProtectPlan, updateProtectPlan } from "@/api/ems/site";

export default {
  data() {
    const validateText = (rule, value, callback) => {
      if (value !== "" && !validText(value)) {
        callback(new Error("只能输入中文、英文、数字和特殊字符!"));
      } else {
        callback();
      }
    };
    return {
      mode: "",
      loading: 0,
      protectionSettings: [],
      protectionPlan: [],
      dialogTableVisible: false,
      formData: {
        id: "",
        siteId: "",
        faultName: "",
        isAlert: 0,
        faultLevel: 1,
        faultDelaySeconds: "",
        releaseDelaySeconds: "",
        description: "",
      },
      rules: {
        faultName: [{ required: true, message: "请输入设备保护名称", trigger: "blur" }],
        isAlert: [{ required: true, message: "请选择是否告警", trigger: "blur" }],
        description: [
          { required: true, message: "请输入设备描述", trigger: "blur" },
          { validator: validateText, trigger: "blur" },
        ],
      },
    };
  },
  computed: {
    ...mapState({
      comparisonOperatorOptions: (state) => state?.ems?.comparisonOperatorOptions || {},
      relationWithPoint: (state) => state?.ems?.relationWithPoint || {},
    }),
  },
  methods: {
    open(id, siteId) {
      const selectedSiteId = siteId || "";
      this.formData.siteId = selectedSiteId;
      this.dialogTableVisible = true;
      if (id) {
        this.formData.id = id;
        this.mode = "edit";
        getProtectPlan(id).then((response) => {
          const data = response?.data || {};
          this.formData = {
            id,
            siteId: selectedSiteId || data?.siteId || "",
            faultName: data?.faultName || "",
            isAlert: data?.isAlert || 0,
            faultLevel: data?.faultLevel || 1,
            faultDelaySeconds: data?.faultDelaySeconds || "",
            releaseDelaySeconds: data?.releaseDelaySeconds || "",
            description: data?.description || "",
          };
          const plan = JSON.parse(data?.protectionPlan || "[]");
          const settings = JSON.parse(data?.protectionSettings || "[]");
          this.$nextTick(() => {
            this.protectionPlan.splice(0, 0, ...plan);
            this.protectionSettings.splice(0, 0, ...settings);
          });
        });
      } else {
        this.mode = "add";
      }
    },
    addRow(type) {
      const item =
        type === "protectionSettings"
          ? {
              deviceId: "",
              deviceName: "",
              deviceCategory: "",
              categoryName: "",
              point: "",
              pointName: "",
              faultValue: "",
              releaseValue: "",
              faultOperator: "",
              releaseOperator: "",
              relationNext: "",
            }
          : {
              deviceId: "",
              deviceName: "",
              deviceCategory: "",
              categoryName: "",
              point: "",
              pointName: "",
              value: "",
            };
      this[type].splice(this[type].length, 0, item);
    },
    deleteRow(index, type) {
      this[type].splice(index, 1);
    },
    querySearchAsync(query, cb, index, type) {
      if (!this.formData.siteId) {
        this.$message({
          type: "warning",
          message: "请先选择站点",
        });
        return cb([]);
      }
      getPointMatchList({
        siteId: this.formData.siteId,
        pageNum: 1,
        pageSize: 100,
        pointId: query || "",
        pointDesc: query || "",
      })
        .then((response) => {
          const data = response?.rows || [];
          cb(
            data.map((item) => {
              const pointLabel = item.pointId || item.pointName || item.dataKey || "";
              const desc = item.pointDesc || "";
              return {
                value: pointLabel,
                pointName: item.pointName || pointLabel,
                pointId: item.pointId || pointLabel,
                pointDesc: desc,
                deviceId: item.deviceId || "",
                deviceName: item.deviceName || "",
                deviceCategory: item.deviceCategory || "",
                categoryName: item.deviceCategory || "",
                label: desc ? `${pointLabel}（${desc}）` : pointLabel,
              };
            })
          );
        })
        .catch(() => cb([]));
    },
    fillPointMetaByPoint(point, index, type) {
      if (!this.formData.siteId || !point) {
        return;
      }
      getPointMatchList({
        siteId: this.formData.siteId,
        pageNum: 1,
        pageSize: 1,
        pointId: point,
      }).then((response) => {
        const row = (response?.rows || [])[0];
        if (!row) return;
        const line = Object.assign({}, this[type][index], {
          point: row.pointId || point,
          pointName: row.pointName || row.pointId || point,
          deviceId: row.deviceId || this[type][index].deviceId,
          deviceName: row.deviceName || this[type][index].deviceName,
          deviceCategory: row.deviceCategory || this[type][index].deviceCategory,
          categoryName: row.deviceCategory || this[type][index].categoryName,
        });
        this[type].splice(index, 1, line);
      });
    },
    handleSelect(data, index, type) {
      const line = Object.assign({}, this[type][index], {
        point: data.pointId || data.value,
        pointName: data.pointName || data.pointId || data.value,
        deviceId: data.deviceId || this[type][index].deviceId,
        deviceName: data.deviceName || this[type][index].deviceName,
        deviceCategory: data.deviceCategory || this[type][index].deviceCategory,
        categoryName: data.categoryName || data.deviceCategory || this[type][index].categoryName,
      });
      this[type].splice(index, 1, line);
    },
    saveDialog() {
      function getToastMsg(name, type, index) {
        return {
          protectionSettings: {
            deviceId: `请选择保护前提第${index}行的设备`,
            deviceCategory: `请选择保护前提第${index}行的设备类型`,
            categoryName: `请选择保护前提第${index}行的设备类型`,
            point: `请选择保护前提第${index}行的点位`,
            pointName: `请选择保护前提第${index}行的点位`,
            faultValue: `请输入保护前提第${index}行的故障值`,
            releaseValue: `请输入保护前提第${index}行的释放值`,
            faultOperator: `请选择保护前提第${index}行的故障值比较关系`,
            releaseOperator: `请选择保护前提第${index}行的释放值比较关系`,
            relationNext: `请选择保护前提第${index}行与下一个点位的关系`,
          },
          protectionPlan: {
            deviceId: `请选择保护方案第${index}行的设备`,
            deviceCategory: `请选择保护方案第${index}行的设备类型`,
            categoryName: `请选择保护方案第${index}行的设备类型`,
            point: `请选择保护方案第${index}行的点位`,
            pointName: `请选择保护方案第${index}行的点位`,
            value: `请输入保护方案第${index}行的故障值`,
          },
        }[type][name];
      }

      this.$refs.addTempForm.validate((valid) => {
        if (!valid) return;
        const {
          id = "",
          siteId = "",
          faultName = "",
          isAlert = 0,
          faultLevel = 1,
          faultDelaySeconds = "",
          releaseDelaySeconds = "",
          description = "",
        } = this.formData;
        const { protectionSettings, protectionPlan } = this;
        let protectionSettingsValidateStatus = true;
        let protectionPlanValidateStatus = true;
        const settingRequiredFields = ["point", "faultOperator", "faultValue", "releaseOperator", "releaseValue"];
        const planRequiredFields = ["point", "value"];

        for (let i = 0; i < protectionSettings.length; i++) {
          const row = protectionSettings[i] || {};
          for (let inner = 0; inner < settingRequiredFields.length; inner++) {
            const key = settingRequiredFields[inner];
            const value = row[key];
            if (![0, "0"].includes(value) && !value) {
              this.$message.error(getToastMsg(key, "protectionSettings", i + 1));
              protectionSettingsValidateStatus = false;
              break;
            }
          }
          if (!protectionSettingsValidateStatus) break;
          if (!row.deviceId) {
            this.$message.error(`请选择保护前提第${i + 1}行的点位（需从点位列表中选择）`);
            protectionSettingsValidateStatus = false;
            break;
          }
          if (protectionSettings[i + 1] && !row.relationNext) {
            this.$message.error(getToastMsg("relationNext", "protectionSettings", i + 1));
            protectionSettingsValidateStatus = false;
            break;
          }
        }

        for (let i = 0; i < protectionPlan.length; i++) {
          const row = protectionPlan[i] || {};
          for (let inner = 0; inner < planRequiredFields.length; inner++) {
            const key = planRequiredFields[inner];
            const value = row[key];
            if (![0, "0"].includes(value) && !value) {
              this.$message.error(getToastMsg(key, "protectionPlan", i + 1));
              protectionPlanValidateStatus = false;
              break;
            }
          }
          if (!protectionPlanValidateStatus) break;
          if (!row.deviceId) {
            this.$message.error(`请选择保护方案第${i + 1}行的点位（需从点位列表中选择）`);
            protectionPlanValidateStatus = false;
            break;
          }
        }

        if (!protectionSettingsValidateStatus || !protectionPlanValidateStatus) return;

        const settings = protectionSettings.map((item) => Object.assign({}, item));
        const plan = protectionPlan.map((item) => Object.assign({}, item));
        this.loading += 1;

        const params = {
          siteId,
          faultName,
          isAlert,
          faultLevel,
          faultDelaySeconds,
          releaseDelaySeconds,
          description,
          protectionSettings: JSON.stringify(settings),
          protectionPlan: JSON.stringify(plan),
        };

        if (this.mode === "add") {
          addProtectPlan(params)
            .then((response) => {
              if (response.code === 200) {
                this.$emit("update");
                this.closeDialog();
              }
            })
            .finally(() => {
              this.loading -= 1;
            });
        } else {
          params.id = id;
          updateProtectPlan(params)
            .then((response) => {
              if (response.code === 200) {
                this.$emit("update");
                this.closeDialog();
              }
            })
            .finally(() => {
              this.loading -= 1;
            });
        }
      });
    },
    closeDialog() {
      this.$emit("clear");
      for (let key in this.formData) {
        this.formData[key] = key === "isAlert" ? 0 : key === "faultLevel" ? 1 : "";
      }
      this.$refs.addTempForm.resetFields();
      this.$set(this, "protectionSettings", []);
      this.$set(this, "protectionPlan", []);
      this.dialogTableVisible = false;
    },
  },
};
</script>

<style scoped lang="scss">
.plan-form {
  background: #f5f8ff;
  border: 1px solid #e8edf7;
  border-radius: 14px;
  padding: 16px;
}

.base-panel {
  background: #fff;
  border: 1px solid #e7ecf6;
  border-radius: 12px;
  padding: 16px;
  margin-bottom: 16px;
}

.panel-title {
  font-size: 15px;
  font-weight: 600;
  color: #1f2d3d;
  margin-bottom: 14px;
}

.base-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px 18px;

  .span-1 {
    grid-column: span 1;
  }

  .span-2 {
    grid-column: span 2;
  }
}

.plan-section {
  background: #fff;
  border: 1px solid #e7ecf6;
  border-radius: 12px;
  padding: 16px;
  margin-bottom: 14px;
}

.section-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 12px;
}

.section-title {
  font-size: 15px;
  font-weight: 600;
  color: #1f2d3d;
  line-height: 1;
  margin-bottom: 6px;
}

.section-desc {
  color: #7b8999;
  font-size: 12px;
}

.section-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

.row-card {
  display: flex;
  gap: 12px;
  align-items: stretch;
  border: 1px solid #e9edf5;
  border-radius: 12px;
  padding: 12px;
  margin-bottom: 12px;
  transition: all 0.2s ease;

  &:hover {
    border-color: #d5e2fb;
    box-shadow: 0 4px 14px rgba(30, 70, 140, 0.08);
  }
}

.row-index {
  width: 30px;
  height: 30px;
  border-radius: 15px;
  background: #eaf1ff;
  color: #2d5ee8;
  font-size: 13px;
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.row-grid {
  flex: 1;
  display: grid;
  gap: 10px;
}

.setting-grid {
  grid-template-columns: 2fr repeat(5, minmax(120px, 1fr));
}

.plan-grid {
  grid-template-columns: 2fr 80px 1fr;
}

.field-block {
  .field-label {
    color: #66788c;
    font-size: 12px;
    margin-bottom: 6px;
  }

  .el-select,
  .el-autocomplete,
  .el-input {
    width: 100%;
  }
}

.eq-block {
  .eq-text {
    height: 36px;
    border: 1px solid #dfe5f0;
    border-radius: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #4a5b6f;
    font-weight: 600;
    background: #f8faff;
  }
}

.row-action {
  width: 72px;
  display: flex;
  align-items: flex-start;
  justify-content: center;
}

.dialog-footer {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

@media (max-width: 1366px) {
  .setting-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .plan-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 992px) {
  .base-grid {
    grid-template-columns: 1fr;

    .span-1,
    .span-2 {
      grid-column: span 1;
    }
  }

  .section-head {
    flex-direction: column;
    align-items: stretch;
  }

  .section-actions {
    flex-wrap: wrap;
  }

  .row-card {
    flex-direction: column;
  }

  .setting-grid,
  .plan-grid {
    grid-template-columns: 1fr;
  }

  .row-action {
    width: 100%;
    justify-content: flex-end;
  }
}
</style>
