<template>
  <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>
              <Col v-for="(paramType,paramIndex) in paramsGroupByTypeList" :span="3" class="paramButton"
                   v-if="item!=='2'&& item !=='1'">
                <el-button icon="el-icon-menu" @click="insertContent(paramType.name, 'variable')">
                  <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-button icon="el-icon-menu" @click="insertContent(funcType.name, 'func')">
                  <span style="color: #5DAAFD">
                     {{
                      funcType.name
                    }}
                  </span>
                </el-button>
              </Col>


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

        </el-tabs>
      </Col>
      <Col style="margin-top: 5%">
        <div class="code-edit">
          <ButtonTitle :label="$t('validation.formulaSetting')"
                       :customStyle="{background: '#F9FBFD',padding:'0 15px 0 15px',width:'100%',margin:'0 !important'}">
            <CustomButton label="validation.test" type="primary" @handleClick="getContent"/>
          </ButtonTitle>
          <codemirror
            :key="yid()"
            ref="codeEditor"
            v-model="formulaStr"
            :options="cmOptions"
            @input="codeMirrorChange"
          ></codemirror>
        </div>
      </Col>
    </Row>

    <Dialog ref="testResult" :title="$t('validation.testresult')">
      <CustomForm :value="testFormula">
        <CustomInput :span="12" required 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 :label="$t('common.cancel')" @handleClick="$refs.testResult.close()"/>
          <CustomButton :label="$t('common.confirm')" @handleClick="submitCheckFunction"/>
        </el-row>

      </template>

    </Dialog>


  </div>

</template>

<script>
import {codemirror} from "vue-codemirror";
import "codemirror/lib/codemirror.css";
import "codemirror/theme/idea.css";
import {listForConfig} from "../../api/business/crm/paralibrary/library";
import Row from "../../components/CustomElement/layout/Row.vue";
import Col from "../../components/CustomElement/layout/Col.vue";
import CustomButton from "../../components/CustomElement/CustomButton.vue";
import {addRule} from "../../api/business/configRule/configRule";
import CustomForm from "../../components/CustomElement/CustomForm/CustomForm.vue";
import CustomInput from "../../components/CustomElement/CustomForm/items/CustomInput.vue";
import {testFormulaValidation} from "../../api/business/crm/paraValidation/paraValidation";
import {isBlank} from "../../utils/common";
import {mapGetters} from "vuex";
import ButtonTitle from "../../components/CustomElement/ButtonTitle.vue";
import yid from "yid";
import {getCommmonPara} from "../../api/business/crm/parabar/parabar";

export default {
  components: {ButtonTitle, CustomInput, CustomForm, CustomButton, Col, Row, codemirror},
  props: {
    parentParamList: {
      type: Array,
      default: () => []
    },
    parentParamTypeList: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
      cmOptions: {
        // 语言及语法模式
        mode: 'text/javascript',
        // 主题
        theme: "idea",
        // 显示函数
        line: true,
        lineNumbers: false,
        // 软换行
        lineWrapping: true,
        // tab宽度
        tabSize: 4,
      },
      lang: 'javascript',
      formulaStr: "",
      formulaValueStr: "",
      paramsList: [...this.parentParamList],
      paramsTypeList: [...this.parentParamTypeList],
      paramsGroupByTypeList: [],
      activeParamType: null,
      usedParamsList: [],
      value: "",
      funList: [
        {
          name: 'SUM',
          value: 'SUM_FUNC'
        }, {
          name: 'IF',
          value: 'IF_FUNC'

        },
        {
          name: 'MAX',
          value: 'MAX_FUNC'
        },
        {
          name: 'MIN',
          value: 'MIN_FUNC'
        },
        {
          name: 'FIND',
          value: 'FIND_FUNC'
        }
      ],
      funKeyMap: {
        'SUM': 'SUM_FUNC',
        'IF': 'IF_FUNC',
        'MAX': 'MAX_FUNC',
        'MIN': 'MIN_FUNC',
        'FIND': 'FIND_FUNC',
      },
      funValueMap: {
        'SUM_FUNC': 'SUM',
        'IF_FUNC': 'IF',
        'MAX_FUNC': 'MAX',
        'MIN_FUNC': 'MIN',
        'FIND_FUNC': 'FIND',
      },
      testFormula: {},
      testResult: null,
    };
  },
  computed: {
    editor() {
      return this.$refs.codeEditor?.codemirror;
    },
    ...mapGetters(["dict"]),

  },
  watch: {},
  mounted() {
    this.focus(this.formulaStr)

  },
  methods: {
    getCommonParams(list) {
      let value = list.map(item => item.elevatorModelId);
      let param = {
        language: this.$i18n.locale,
        relatedModel: value,
        modelCount: value.length,
      }
      getCommmonPara(param).then(res => {
        if (res) {
          this.paramsList = res.map(item => {
            return {
              name: item.paraName,
              value: item.paraCode,
              type: item.paraCategory,
              key: item.paraId
            };
          });
          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'
          ]
        }
      })


    },
    yid,
    initTypeNames(val) {
      if (typeof val === 'string') {
        console.log(this.dict['para_category'])
        let search = this.dict['para_category'].find(item => 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);
        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;
    },
    async submitCheckFunction() {
      //公式code替换
      Object.keys(this.funKeyMap).forEach(key => {
        let value = this.funKeyMap[key];
        this.formulaValueStr = this.formulaValueStr.replaceAll(key, `$@$${value}$@$`);
      })
      let {data} = await testFormulaValidation({
        formulaValueStr: this.formulaValueStr.replaceAll("，", ",").replaceAll("（", "(").replaceAll("）", ")"),
        formulaValueMap: this.testFormula,
      });
      this.testResult = data.calculateValue;
      if (this.testResult === 'NaN' || data.result === 'NG') {
        this.testResult = "NG";
      } else {
        this.testResult = `OK-${data.calculateValue}`;
      }
      return new Promise((resolve, reject) => {
        if (data) {
          if (data.result && data.result === 'NG') {
            this.$message.error(this.$t('validation.errorMsg'));
            reject(this.$t('validation.errorMsg'));
          } else {
            resolve();
          }
        } else {
          reject(this.$t('validation.errorMsg'));
        }
      })


    },
    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));
      });
    },
    async initDataContentByCode(str, flag = false, parentParamsList) {
      let formula = str
      // let newStr = str.replace(/[\+\-\*\/]/g, function (match, index, original) {
      //   if (index) {
      //     return '|' + match + '|'
      //   }
      // });
      formula = formula.replace(/(\$_\$|\$@\$)/g, '|$1|');


      // 变量CODE替换
      console.log(flag, parentParamsList)
      let sortParamsList = flag ? parentParamsList : [...this.paramsList];
      sortParamsList = this.sortByKey(sortParamsList, 'value');

      let funcValue = Object.keys(this.funKeyMap).map(key => this.funKeyMap[key]);

      let regex = /[+\-*/]/;

      let rightRegex = /\)+/g;
      //公式code替换
      console.log(sortParamsList, 'sortParamsList')
      formula.split('|').filter(item => !isBlank(item) && item !== '$_$' && item !== '$@$').forEach((item, index) => {
        if (!regex.test(item) && !funcValue.includes(item) && !rightRegex.test(item)) {
          let search = sortParamsList.find(it => it.value === item)
          if (search) {
            this.insertContent(search.name, 'variable')
          }
        } else if (funcValue.includes(item) && !regex.test(item)) {
          this.insertContent(this.funValueMap[item], 'func')
        } else {
          if (')' !== item && /\)+/g.test(item)) {
            let rightStr = item.slice(0, -1);
            this.insertContent(rightStr, null)
          } else {
            this.insertContent(item, null)
          }

        }
      })


      // sortParamsList.forEach(item => {
      //   // 通过初始item 完全 匹配，并进行替换
      //   formula = formula.replaceAll('$_$' + item.value + '$_$', item.name);
      // })


      // newStr.split('|').filter(item=>!isBlank(item)).forEach((item,index)=>{
      //   if(item.includes('$_$')){
      //     let search =sortParamsList.find(it=>it.value === item.replaceAll('$_$', ''))
      //     if(search){
      //       this.insertContent(search.name, 'variable',search.value);
      //     }
      //
      //   }else if(item.includes('$@$')){
      //     let search =this.funList.find(it=>it.value === item.replaceAll('$@$', ''))
      //     console.log(search,'search')
      //     console.log(item,'item')
      //     if(search){
      //       this.insertContent(search.name, 'func',search.value);
      //     }
      //   }else {
      //     if(index-1>=0 && !newStr.split('|')[index-1].includes('$@$')&& !isBlank(item)){
      //       this.insertContent(item);
      //     }
      //   }
      // })
    },


    getContent() {
      if (isBlank(this.formulaValueStr)) {
        return;
      }

      this.usedParamsList = [];
      let formula = this.formulaValueStr;
      // 变量CODE替换
      let sortParamsList = [...this.paramsList];
      sortParamsList = this.sortByKey(sortParamsList, 'name');
      sortParamsList.forEach(item => {
        // 通过初始item 完全 匹配，并进行替换
        formula = formula.replaceAll(item.name, '$_$' + item.value + '$_$');
      })
      this.formulaValueStr = formula;

      let usedParamsList = this.getParam(formula);
      const valueSet = new Set(usedParamsList)
      usedParamsList = Array.from(valueSet);
      for (let value of usedParamsList) {
        let item = sortParamsList.find(item => item.value === value.replaceAll('$_$', ''));
        if (item) {
          this.usedParamsList.push({
            name: item.name,
            value: item.value,
            key: item.value
          })
        }
      }
      this.$refs.testResult.open(true);
    },
    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 (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, 'name');
        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;
          }
        });
      }
    }
    ,
  },
};
</script>

<style scoped>


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

  .CodeMirror-scroll {
    width: 100%;
  }
}

</style>
