<template>
  <div class="app-container">
    <div class="top">
      <div class="account-title">{{ $t(initTitle) }}</div>
      <div class="button-group">
        <el-button v-if="type!==4" type="primary" icon="el-icon-circle-check" @click="handleConfirm">
          {{ $t('common.confirm') }}</el-button>
        <el-button  @click="$tab.closeOpenPage('/para/validationConfig')" size="mini" plain style="width: 93px;" icon="el-icon-remove-outline">
          {{ $t('common.cancel') }}</el-button>
      </div>
    </div>
    <CustomCard :show-save="type!==4" :show-cancel="true" :label="initTitle" @Confirm="handleConfirm"
                :show-header="false" @cancel="$tab.closeOpenPage('/para/validationConfig')">
      <CustomForm ref="InputForm" :value="basicInfo" :disabled="type===4">
        <CustomInput class="eightChar" :maxlength="100" required label="validation.ruleName" prop="caseName"/>
        <CustomInput class="eightChar" required label="validation.NgMessage" prop="resultFalse"/>
        <CustomInput class="eightChar" required label="validation.NgMessageUS" prop="resultFalseUS"/>
        <CustomInput class="eightChar" required label="validation.NgMessageRU" prop="resultFalseRU"/>
        <CustomInput class="eightChar" required label="validation.NgMessageES" prop="resultFalseES"/>
        <CustomSwitch class="eightChar" prop="quotationFlag" label="是否用于报价"/>
        <CustomSwitch class="eightChar" prop="civilFlag" label="是否用于土建"/>
      </CustomForm>
      <Row>
        <ElevatorModelTable :span="24" :sm-span="24" :lg-span="24" :md-span="24" :xs-span="24" :disabled="type===4"
                            ref="relationEnters" :modal-data="relationEnters"
                            @handleConfirm="handleModelTableConfirm"
                            @handleDeleteRow="handleDeleteRow"/>
      </Row>
    </CustomCard>

    <CustomCard :show-header="false" style="margin-top: 1%">
      <Row>
        <Col>
          <div class="picker">
            <Row style="width: 100%">
              <Col>
                <el-tabs @tab-click="handleTabClick" >
                  <el-tab-pane v-for="(item ,index) in paramsTypeList" :key="index"
                               :label="initTypeNames(item)">
                    <Row style="margin-bottom: 1%">
                      <Col v-for="(commonParam) in commonParamsList" :span="3" class="paramButton"
                           v-if="index===0">
                        <el-button icon="el-icon-menu" @click="insertContent(commonParam.paramName, 'variable')"
                                   :disabled="type===4">
                          <span style="color: #5DAAFD">{{ commonParam.paramName }}</span>
                        </el-button>
                      </Col>

                      <Col v-for="(paramType,paramIndex) in paramsGroupByTypeList" :key="paramIndex" :span="3"
                           class="paramButton"
                           v-if="item!=='2'&& item !=='1'">
                        <el-button icon="el-icon-menu" @click="insertContent(paramType.name, 'variable')"
                                   :disabled="type===4">
                          <span style="color: #5DAAFD">{{ paramType.name }}</span>
                        </el-button>
                      </Col>
                      <Col v-for="(funcType,funcIndex) in funList()" :span="3" class="paramButton" v-if="item==='2'">
                        <el-tooltip>
                          <template #content>
                            {{funcType.tip}}
                          </template>
                          <el-button icon="el-icon-menu" @click="insertContent(funcType.name, 'func')"
                                     :disabled="type===4">
                            <span style="color: #5DAAFD">{{ funcType.name }}</span>
                          </el-button>
                        </el-tooltip>
                      </Col>
                      <Col v-for="(logicType,logicIndex) in logicOperation()" :span="3" class="paramButton"
                           v-if="item==='2'">
                        <el-button icon="el-icon-menu" @click="insertContent(logicType.name, 'logic')"
                                   :disabled="type===4">
                          <span style="color: #5DAAFD">{{ logicType.name }}</span>
                        </el-button>
                      </Col>


                    </Row>
                  </el-tab-pane>

                </el-tabs>
              </Col>

            </Row>
          </div>
        </Col>
      </Row>
    </CustomCard>


    <CustomCard cardHeight="300px" :show-header="false" style="margin-top: 1%">
      <ButtonTitle :label="$t('validation.formulaSetting')" style="position: relative;top: -17px;left: -27px;width: 103%"
                   :customStyle="{background: '#F9FBFD',padding:'5px',width:'100%',margin:'0 !important'}">
        <CustomButton v-if="type!==4" label="validation.test" type="primary" icon="el-icon-document" @handleClick="getContent"/>
      </ButtonTitle>
      <div class="code-edit">


        <codemirror

          ref="codeEditor"
          v-model="formulaStr"
          :options="cmOptions"
          @input="codeMirrorChange"
        ></codemirror>
      </div>
    </CustomCard>

    <Dialog ref="testResult" :title="$t('validation.testresult')" @close="closeCheck">
      <CustomForm :value="testFormula">
        <CustomInput :span="12"  v-for="(item ,index) in  usedParamsList" :label="`${item.name}`"
                     :prop="`$_$${item.value}$_$`"
                     :key="index"/>
        <el-form-item :label="$t('validation.testresult')">
          <span>{{ testResult }}</span>
        </el-form-item>
      </CustomForm>

      <template #footer>
        <el-row style="text-align: end">
          <CustomButton type="primary" icon="el-icon-circle-check" :label="$t('common.confirm')"
                        @handleClick="submitCheckFunction"/>
          <CustomButton icon="el-icon-remove-outline" :label="$t('common.cancel')" @handleClick="closeCheck()"/>
        </el-row>

      </template>
    </Dialog>
  </div>
</template>

<script>

import CustomForm from "../../../components/CustomElement/CustomForm/CustomForm.vue";
import CustomCard from "../../../components/CustomElement/CustomCard.vue";
import CustomInput from "../../../components/CustomElement/CustomForm/items/CustomInput.vue";
import ElevatorModelSelect from "../../components/ElevatorModelTable.vue";
import ElevatorModelTable from "../../components/ElevatorModelTable.vue";
import FooterButtonBottom from "../../../components/element/footerButtonBottom.vue";
import FormulaCodeMirror from "../../components/FormulaCodeMirror.vue";
import Row from "../../../components/CustomElement/layout/Row.vue";
import Col from "../../../components/CustomElement/layout/Col.vue";
import CustomButton from "../../../components/CustomElement/CustomButton.vue";
import {buildRegexFromArray, isBlank} from "@/utils/common";
import {
  getCommonParamList,
  getInfoByIdValidation,
  saveOrUpdateValidation,
  testFormulaValidation
} from "@/api/business/crm/paraValidation/paraValidation";
import {getCommmonPara} from "@/api/business/crm/parabar/parabar";
import yid from "yid";
import ButtonTitle from "../../../components/CustomElement/ButtonTitle.vue";
import {mapGetters} from "vuex";
import {codemirror} from "vue-codemirror";
import {
  analysisFormula,
  funKeyMap,
  funList, getContent,
  initReplaceCodeList, isValidString,
  logicKeyMap,
  logicOperation,
  logicValueMap, matchStr, testSubmitCheckFunction
} from "@/utils/formula";

export default {
  name:"SecondaryPageValid",
  components: {
    codemirror,
    ButtonTitle,
    CustomButton,
    Col,
    Row,
    FormulaCodeMirror,
    FooterButtonBottom, ElevatorModelTable, ElevatorModelSelect, CustomInput, CustomCard, CustomForm
  },
  data() {
    return {
      basicInfo: {
        quotationFlag: "1",
        civilFlag: "0",
      },
      relationEnters: [],
      type: null,
      relationEntersShow: true,
      cmOptions: {
        // 语言及语法模式
        mode: 'text/javascript',
        // 主题
        theme: "idea",
        // 显示函数
        line: true,
        lineNumbers: false,
        // 软换行
        lineWrapping: true,
        // tab宽度
        tabSize: 4,
        readonly:  'nocursor'
      },
      lang: 'javascript',
      formulaStr: "",
      formulaValueStr: "",
      paramsList: [],
      paramsTypeList: [],
      paramsGroupByTypeList: [],
      paramsGroupByShow: true,
      activeParamType: null,
      usedParamsList: [],
      value: "",

      testFormula: {},
      testResult: null,
      commonParamsList: [],

    };
  },
  computed: {
    initTitle() {
      switch (this.type) {
        case 1:
          return "validation.addRule";
        case 2:
          return "validation.editRule";
        case 4:
          return "validation.detailRule";
      }
    },
    editor() {
      return this.$refs.codeEditor?.codemirror;
    },
    ...mapGetters(["dict"]),
  },
  watch: {
    relationEnters: {
      handler(val, oldVal) {
        if (val) {
          this.getCommonParams(val);
        }

      },
      deep: true,
      immediate: true
    }
  },
  methods: {
    logicOperation() {
      return logicOperation
    },
    funList() {
      return funList
    },
    yid,
    async getCommonParams(list) {
      let value = list.map(item => item.elevatorModelId);
      let param = {
        language: this.$i18n.locale,
        relatedModel: value,
        modelCount: value.length,
      }
      let res = await getCommmonPara(param);
      if (res) {
        this.paramsList = res.map(item => {
          return {
            name: item.paraName,
            value: item.paraCode,
            type: item.paraCategory,
            key: item.paraId,
            inputType: item.inputType,
          };
        });
        this.paramsTypeList = this.paramsList.map(item => item.type);
        let map = new Set(this.paramsTypeList);
        this.paramsTypeList = Array.from(map);
        this.paramsTypeList = ['1',
          ...this.paramsTypeList,
          '2'
        ]
      }

    },

    async handleModelTableConfirm(val) {
      this.relationEnters = [...val];
      this.paramsGroupByShow = false;
      await this.getCommonParams(this.relationEnters)
      this.paramsGroupByTypeList = this.paramsList.filter(item => item.type === this.activeParamType);
      // @Date 2024/6/11 13:28 @Author jubs 😀 @description: 确保变更梯型后，参数还是共有的，如果不是则需要清空
      let conditionFormulaAnalysis = this.formulaStr;
      conditionFormulaAnalysis = analysisFormula(conditionFormulaAnalysis, initReplaceCodeList(this.paramsList));
      if (val === [] || val === null || val.length === 0) {
        this.formulaStr = "";
        this.formulaValueStr = "";
        this.editor.setValue("");
        this.editor.clearHistory();
      } else {

        if (!isValidString(conditionFormulaAnalysis)) {
          // 如果还存在未被替换的参数，则表示 变更梯型后，参数未共有
          this.formulaStr = "";
          this.formulaValueStr = "";
          this.editor.setValue("");
          this.editor.clearHistory();
        }

      }
      this.paramsGroupByShow = true;


    },
    handleDeleteRow(val) {
      this.basicInfo.deleteRelationEnterIds = val
      if (this.$refs.relationEnters.tableData.length === 0) {
        this.paramsList = [];
        this.paramsTypeList = ['1',
          '2'
        ]
        this.editor.setValue("");
        this.editor.clearHistory();
      } else {
        this.getCommonParams(this.$refs.relationEnters.tableData)
      }


    },

    async handleConfirm() {
      await this.$refs.InputForm.validate();
      this.relationEnters = JSON.parse(JSON.stringify(this.$refs.relationEnters.tableData))
      if (isBlank(this.relationEnters) || this.relationEnters.length === 0) {
        this.$modal.msgError((this.$t('validation.atLeastModel')));
        return;
      }
      let conditionFormula = this.formulaStr;
      let conditionFormulaAnalysis = this.formulaStr;
      if (isBlank(conditionFormula)) {
        this.$modal.msgError(this.$t('validation.formulaSetting') + this.$t('common.requiredMsg'));
        return;
      }
      conditionFormulaAnalysis = analysisFormula(conditionFormulaAnalysis, initReplaceCodeList(this.paramsList));

      // if (matchStr(conditionFormulaAnalysis)) {
      //   // 如果还存在未被替换的参数，则表示 变更梯型后，参数未共有
      //   this.$modal.msgError("请确保参数在梯型中存在！");
      //   return;
      // }

      conditionFormula = this.formulaValueStr
      let row = {
        ...this.basicInfo,
        relationEnters: this.relationEnters,
        operationFlag: this.type,
        conditionFormula: conditionFormula.replaceAll(" ", ""),
        conditionFormulaAnalysis: conditionFormulaAnalysis,
      }
      saveOrUpdateValidation(row).then(res => {
        if (res.code === 200) {
          let msg = this.type === 1 ? this.$t('common.addSuccess') : this.$t('common.editSuccess');
          this.$message.success(msg);
          this.$tab.closeOpenPage('/para/validationConfig')
        }
      })
    },
    initDataInfo(id) {
      getInfoByIdValidation(id).then(async res => {
        if (res.data) {
          let basicInfo = {...res.data}
          this.relationEnters = [...basicInfo.relationEnters];
          let value = this.relationEnters.map(item => item.elevatorModelId);
          let param = {
            language: this.$i18n.locale,
            relatedModel: value,
            modelCount: value.length,
          }
          getCommmonPara(param).then(ress => {
            if (ress) {
              this.paramsList = ress.map(item => {
                return {
                  name: item.paraName,
                  value: item.paraCode,
                  type: item.paraCategory,
                  key: item.paraId,
                  inputType: item.inputType,
                };
              });
              this.paramsTypeList = this.paramsList.map(item => item.type);
              let map = new Set(this.paramsTypeList);
              this.paramsTypeList = Array.from(map);
              this.paramsTypeList = ['1',
                ...this.paramsTypeList,
                '2'
              ]
              this.basicInfo = {...basicInfo}
              this.initDataContentByCode(basicInfo.conditionFormula);
              if(this.type=='4'){
                this.$refs.codeEditor?.codemirror.setOption('readOnly',true);
                this.editor.blur();
              }
            }
          })

        }
      })
    },
    initTypeNames(val) {
      if (typeof val === 'string') {
        let search = this.dict['para_category'].find(item => {
          return item.value == val
        });
        if (search) {
          return search.label;
        } else if (val === '1') {
          return this.$t('validation.commonParameters')
        } else {
          return this.$t('validation.Logical')
        }
      }
    },
    handleTabClick(val) {
      if (val.index === '0') {
      } else if (val.index === this.paramsTypeList.length - 1) {
      } else {
        let search = this.dict['para_category'].find(item => item.label === val.label);
        if (search) {
          this.activeParamType = search.value;
          this.paramsGroupByTypeList = this.paramsList.filter(item => item.type === this.activeParamType);
        }

      }

    },
    getParam(str) {
      let matchList = [];
      const regex = /(\$_\$.*?\$_\$)/g;
      const matches = str.match(regex);
      if (matches) {
        matches.forEach(match => {
          matchList.push(match)
        });
      }
      return matchList;
    },
    closeCheck() {
      this.testFormula = {};
      this.testResult = null;
      this.$refs.testResult.visible = false;
    },
    async submitCheckFunction() {
      this.formulaValueStr = this.formulaStr
      return testSubmitCheckFunction(this, this.formulaValueStr, this.paramsList, this.testFormula, this.usedParamsList)
    },
    sortByKey(array, key) {
      return array.sort(function (a, b) {
        var x = !isBlank(key) ? a[key] : a;
        var y = !isBlank(key) ? b[key] : b;
        return ((x > y) ? -1 : ((x < y) ? 1 : 0));
      });
    },
    initDataContentByCode(str) {
      let formula = str
      // 变量CODE替换
      let sortParamsList = initReplaceCodeList(this.paramsList);
      sortParamsList = sortParamsList.map(item => item.name);
      sortParamsList.push("（");
      sortParamsList.push("）");
      sortParamsList.push("，");
      sortParamsList.push(",");

      formula = formula.replace(buildRegexFromArray(sortParamsList), '|$1|');
      let funcValue = Object.keys(funKeyMap);
      let logicValue = Object.keys(logicKeyMap);
      let regex = /[+\-*/]/;
      let rightRegex = /\)+/g;
      let leftRegex = /\(+/g
      let judgeRegex = /[><]/
      //公式code替换
      console.log(formula.split('|'))
      console.log(formula)
      formula.split('|').forEach((item, index) => {
        if (funcValue.includes(item) && !regex.test(item)) {
          this.insertContent(item, 'funcInit')
        } else if (logicValue.includes(item)) {
          this.insertContent(item, 'logic');
        } else if (regex.test(item) || judgeRegex.test(item) || leftRegex.test(item) || rightRegex.test(item) || item === "," || item === "，"
          || item.includes("\"") || item.includes("==")) {
          this.insertContent(item, null)
        } else {
          if (item != " ") {
            this.insertContent(item, 'variable')
          }
        }
      })

    },
    getContent() {
      getContent(this);
    },
    codeMirrorChange() {
      //获取 editor 的内容
      this.formulaValueStr = this.formulaStr;
    },
    /**
     * editor 中的对内容进行处理
     * @param label
     * @param type variable | func，variable为表单变量，需标记，func 为函数，也需要做标记
     */
    insertContent(label, type) {
      const from = this.editor.getCursor();
      if (type === 'variable') {
        this.editor.replaceSelection(label);
        const to = this.editor.getCursor();
        this.markText(from, to, label, 'cm-field');
      } else if (type === 'func') {
        this.editor.replaceSelection(`${label}()`);
        const to = this.editor.getCursor();
        this.markText(from, {line: to.line, ch: to.ch - 2}, label, 'cm-func');
        this.editor.setCursor({line: to.line, ch: to.ch - 1});
      } else if (type === 'funcInit') {
        this.editor.replaceSelection(`${label}`);
        const to = this.editor.getCursor();
        this.markText(from, {line: to.line, ch: to.ch }, label, 'cm-func');
      } else if (type === 'logic') {
        this.editor.replaceSelection(` ${label} `);
        const to = this.editor.getCursor();
        this.markText(from, to, label, 'cm-logic');
      } else if (typeof label === 'string') {
        this.editor.replaceSelection(label);
      }
      this.editor.focus();
    },

    autoMarkText() {
      if (this.formulaStr) {
        this.autoMark(this.formulaStr);
        this.focus(this.formulaStr);
      }
    }
    ,
    focus(value) {
      this.editor.setCursor({
        line: 0,
        ch: value ? value.length : 0
      });
      this.editor.focus()
    }
    ,
    markText(from, to, label, className) {
      if (className === void 0) {
        className = "cm-func";
      }
      let text = document.createElement("span");
      text.className = className;
      text.innerText = label;
      this.editor.markText(from, to, {
        atomic: true,
        replacedWith: text,
      });
    }
    ,
    /**
     * 解析 editor 的内容，分别对表单变量和函数进行标记
     */
    autoMark() {
      const editor = this.editor;
      const lines = editor.lineCount();

      for (let line = 0; line < lines; line++) {
        const content = editor.getLine(line);
        // 标记函数调用,匹配一个或多个连续的大写字母，后面可以有任意数量的空白字符，再紧跟一个左括号

        content.replace(/\$_\$.*?\$_\$\(/g, (_, func, pos) => {
          this.markText({line: line, ch: pos}, {line: line, ch: pos + func.length}, func, 'cm-func');
          return _;
        });
        // 标记表单变量,这应该是动态获取，自行替换即可
        let sortParamsList = [...this.paramsList];
        sortParamsList = this.sortByKey(sortParamsList, 'value');
        sortParamsList = sortParamsList.map(v => v.name);


        let vars = [...sortParamsList];
        vars.forEach(v => {
          let from = 0;
          let idx = -1;
          while (~(idx = content.indexOf(v, from))) {
            this.markText({line: line, ch: idx}, {line: line, ch: idx + v.length}, v, 'cm-field');
            from = idx + v.length;
          }
        });
      }
    }
    ,

  },


  created() {

  },
  mounted() {
    let {type} = this.$route.query;

    if (!isBlank(type)) {
      this.type = parseInt(type);
      if (type !== '4') {
        getCommonParamList().then(res => {
          this.commonParamsList = res.data;
        })
      }
      if (type !== '1') {
        getInfoByIdValidation(this.$route.query.id).then(async res => {
          if (res.data) {
            this.initDataInfo(this.$route.query.id);
          }
        })
      }
    }
  },


}


</script>

<style scoped>
  .top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 10px;
  }
  .account-title {
    font-family: Arial, Arial;
    font-weight: bold;
    font-size: 18px;
    line-height: 21px;
  }
  .button-group {
    display: flex;
  }
.paramButton {
  .el-button {
    color: #E4F1FF;

  }

  .el-icon-menu {
    color: #5DAAFD;
  }

}

.picker {

  text-align: left;

  .code-edit {
    height: 240px;
    border-radius: 6px;
    border: 1px solid #e8e9eb;
  }
}

.top-title {
  background-color: #fafafa;
  height: 30px;
  vertical-align: center;
  line-height: 30px;
  padding-left: 10px;
  border-radius: 4px 4px 0 0;
  border-bottom: none;
}

/deep/ .CodeMirror {
  height: 200px !important;
  /*表单变量样式*/

  .cm-field {
    background: #007bff;
    padding: 3px 5px;
    border-radius: 3px;
    color: #fff;
    margin: 0 1px;
  }

  /*函数样式*/

  .cm-func {
    font-weight: bold;
    color: #ae4597;
    line-height: 14px;
    margin: 0 1px;
    padding: 0 2px;
  }

  .cm-logic {
    font-weight: bold;
    color: #00afff;
    line-height: 14px;
    margin: 0 1px;
    padding: 0 2px;
  }

  .CodeMirror-scroll {
    height: 200px !important;
  }
}
</style>
<style lang="scss" scoped>
  ::v-deep .el-tabs__header{
    background-color: #F9FBFD;
  }
  ::v-deep .el-tabs__item{

  }
</style>

