<template>
  <div class="promqlInput" :class=" errorMsg || appendMsg ? 'mb10' : ''">
    <div class="query-row">
      <!--explore页面的样式-->
      <template v-if="styleType == 1">
        <div v-if="plugins.indexOf('metric-selector') > -1">
          <el-dropdown class="metric-selector">
            <el-dropdown-menu style="display: none"></el-dropdown-menu>
            <button
              class="top-tool-btn top-tool-btn--text"
              type="button"
              @click="toggleDropdown"
            >
              {{
                type === "log" ? $t("overall.logLabels") : $t("overall.metric")
              }}
              <i class="nz-icon nz-icon-arrow-down" style="font-size: 12px"></i>
            </button>
            <el-cascader-panel
              v-show="dropDownVisible"
              ref="metricSelector"
              slot="dropdown"
              v-model="cascaderValue"
              v-clickoutside="closeDropdown"
              v-my-loading="tempBoxShowLoading"
              :options="metricOptions"
              v-if="type !== 'log'"
              :props="cascaderProps"
              @change="metricChangeNew"
              style="margin-top: 5px"
            >
              <template slot-scope="{ node, data }">
                <div
                  :class="[
                    'nz-cascade',
                    data.temp && !data.child ? 'nz-cascade-temp' : '',
                    data.more ? 'cascader-panel-more' : '',
                  ]"
                  @click="
                    () => {
                      lazyLoad(node, data);
                    }
                  "
                  :title="data.label"
                >
                  <i class="nz-icon nz-icon-template2"></i>
                  {{ data.label }}
                  <i v-if="data.more" class="nz-icon nz-icon-arrow-down"></i>
                </div>
              </template>
            </el-cascader-panel>
            <el-cascader-panel
              v-else
              v-show="dropDownVisible"
              ref="metricSelector"
              slot="dropdown"
              v-model="cascaderValue"
              v-clickoutside="closeDropdown"
              v-my-loading="tempBoxShowLoading"
              :loading="loading"
              :props="cascaderProps"
              @change="logLabelChange"
              style="margin-top: 5px"
            >
              <template slot-scope="{ node, data }">
                <div :title="data.label" class="nz-cascade">
                  {{ data.label }}
                </div>
              </template>
            </el-cascader-panel>
          </el-dropdown>
        </div>

        <div
          v-if="plugins.indexOf('metric-input') > -1"
          class="input-box"
          @click="dropDownVisible = false"
        >
          <div
            :id="pqid + 'editor'+index"
            v-if="type !== 'log'"
            class="not-fixed-height no-resize no-close"
          >
          </div>
          <!-- <div id='editor'
          class="not-fixed-height no-resize no-close"
          >
          </div> -->
<!--          <el-input-->
<!--            v-if="type == 'log'"-->
<!--            :id="inputId"-->
<!--            v-model="expressionList[index]"-->
<!--            size="small" :rows="1"-->
<!--            autosize-->
<!--            class="not-fixed-height no-resize"-->
<!--            type="textarea"-->
<!--            show-word-limit maxlength="256"-->
<!--            @input="metricKeyDown"-->
<!--            @keyup.enter.native="expressionChange"-->
<!--            ref="elInput"-->
<!--          >-->
<!--          </el-input>-->
          <div>
            <MonacoEditor
              v-if="type == 'log'"
              v-model="expressionList[index]"
              theme="nz"
              class="not-fixed-height no-resize"
              ref="monacoEditor"
              style="border: 1px solid #dedede;"
              :style="{
                height: monacoEditorHeight + 'px'
              }"
              language="logql"
              :options="MONACO_EDITOR_OPTIONS"
              @editorWillMount="handelBeforeMount"
              @editorDidMount="handleMount"
              @change="expressionChange"
            />
          </div>

          <div v-if="errorMsg" class="append-msg error" style="position: absolute">
            <span>{{ errorMsg }}</span>
          </div>
          <div v-if="appendMsg" class="append-msg error" style="position: absolute">
            <span>{{ appendMsg }}</span>
          </div>
        </div>

        <div class="top-tool-btn-group">
          <button
            v-if="plugins.indexOf('enable') > -1"
            class="top-tool-btn"
            :title="state?$t('overall.enabled'):$t('profile.close')"
            @click="enableExpression"
          >
            <i  v-if="state" class="nz-icon nz-icon-mimakejian"></i>
            <i v-else class="nz-icon nz-icon-mimabukejian" style="fontSize:16px"></i>
          </button>
          <button
            v-if="plugins.indexOf('history') > -1"
            class="top-tool-btn"
            :title="$t('overall.history')"
            @click.stop="showHistoryBox(!historyshow)"
          >
            <i class="nz-icon nz-icon-time" style="fontSize:16px"></i>
          </button>
          <button
            v-if="plugins.indexOf('add') > -1"
            class="top-tool-btn"
            :title="$t('tip.add')"
            @click="addExpression"
          >
            <i class="nz-icon nz-icon-plus"></i>
          </button>
          <button
            v-if="plugins.indexOf('copy') > -1"
            class="top-tool-btn"
            @click="copyExpression"
            :title="$t('overall.duplicate')"
          >
            <i class="nz-icon nz-icon-override"></i>
          </button>
          <button
            v-if="plugins.indexOf('remove') > -1"
            class="top-tool-btn"
            @click="removeExpression"
            :title="$t('overall.delete')"
          >
            <i class="nz-icon nz-icon-minus"></i>
          </button>
        </div>
        <explore-history v-if="historyshow" :type="type" @close="showHistoryBox(false)" @selectHistory="selectHistory"/>
      </template>
      <!--right-box里的样式-->
      <template v-if="styleType === 2 || styleType === 3">
        <el-row
          v-if="
            plugins.indexOf('metric-input') > -1 ||
            plugins.indexOf('metric-selector') > -1
          "
          style="width: 100%"
        >
          <el-col
            :class="[
              plugins.indexOf('metric-selector') > -1
                ? 'metric-selector-title'
                : 'metric-null-title',
            ]"
          >
            <el-dropdown
              class="metric-selector"
              style="width: 100%"
              v-if="plugins.indexOf('metric-selector') > -1"
            >
              <el-dropdown-menu style="display: none"></el-dropdown-menu>
              <span
                :class="{ 'expr-title': projectRightBox }"
                style="cursor: pointer;width: 100%;display: inline-block"
                @click="toggleDropdown"
                >{{
                  type === "log"
                    ? $t("overall.logLabels")
                    : $t("overall.metric")
                }}<i
                  class="nz-icon nz-icon-arrow-down"
                  style="
                    font-size: 14px;
                    -webkit-transform: scale(0.75);
                    display: inline-block;
                  "
                ></i
              ></span>
              <el-cascader-panel
                v-my-loading="tempBoxShowLoading"
                v-show="dropDownVisible"
                v-clickoutside="closeDropdown"
                v-model="cascaderValue"
                style="text-align: left; margin-top: 5px"
                slot="dropdown"
                ref="metricSelector"
                v-if="type !== 'log'"
                :props="{ emitPath: false }"
                :options="metricOptions"
                @change="metricChangeNew"
              >
                <template slot-scope="{ node, data }">
                  <div
                    :class="[
                      'nz-cascade',
                      data.temp && !data.child ? 'nz-cascade-temp' : '',
                      data.more ? 'cascader-panel-more' : '',
                    ]"
                    @click="
                      () => {
                        lazyLoad(node, data);
                      }
                    "
                    :title="data.label"
                  >
                    <i class="nz-icon nz-icon-template2"></i>
                    {{ data.label }}
                    <i v-if="data.more" class="nz-icon nz-icon-arrow-down"></i>
                  </div>
                </template>
              </el-cascader-panel>
              <el-cascader-panel
                v-else
                v-show="dropDownVisible"
                ref="metricSelector"
                slot="dropdown"
                v-model="cascaderValue"
                v-clickoutside="closeDropdown"
                v-my-loading="tempBoxShowLoading"
                :loading="loading"
                :props="cascaderProps"
                @change="logLabelChange"
              >
                <template slot-scope="{ node, data }">
                  <div :title="data.label" class="nz-cascade">
                    {{ data.label }}
                  </div>
                </template>
              </el-cascader-panel>
            </el-dropdown>
          </el-col>
          <el-col
            :class="
              plugins.indexOf('metric-selector') > -1
                ? 'metric-selector-input-box'
                : 'metric-null-input-box'
            "
            :style="{ height: '100%' }"
          >

            <div
              class="input-box"
              @click="dropDownVisible = false"
              v-if="plugins.indexOf('metric-input') > -1"
            >
            <div
              :id="pqid + 'editor'+index"
              v-if="type !== 'log'"
              class="not-fixed-height no-resize no-close"
            >
            </div>
            <!-- <div id="editor"
            class="not-fixed-height no-resize no-close"
                ref="elInput"

            ></div> -->
               <el-input
                v-model="expressionList[index]"
                v-if="type === 'log'"
                @input="metricKeyDown"
                autosize
                type="textarea"
                :maxlength="styleType === 3 ? 512 : 4096"
                show-word-limit
                size="small" :rows="1"
                class="not-fixed-height no-resize"
                ref="elInput"
              ></el-input>
            </div>
            <div class="append-msg error" v-if="errorMsg">
              <span>{{ errorMsg }}</span>
            </div>
            <div class="append-msg error" v-if="appendMsg">
              <span>{{ appendMsg }}</span>
            </div>
          </el-col>
        </el-row>
      </template>
    </div>
    <div v-if="styleType == 2 && showRemove">
      <div
        class="option"
        @click="addExpression"
        :title="$t('tip.add')"
        v-if="plugins.indexOf('add') > -1"
      >
        <i class="nz-icon nz-icon-plus"></i>
      </div>
      <div
        class="option"
        style="margin-left: 5px; line-height: 32px"
        @click="removeExpression"
        :title="$t('overall.delete')"
        v-if="plugins.indexOf('remove') > -1"
      >
        <i class="nz-icon nz-icon-minus"></i>
      </div>
    </div>

    <el-dialog
      :visible.sync="tempBoxShow"
      :append-to-body="true"
      :width="'auto'"
      :custom-class="'nz-temp-box'"
      :destroy-on-close="true"
      @closed="tempBoxClose"
      center
    >
      <el-form
        v-model="tempBox"
        class="temp-form-box"
        ref="tempFormBox"
        v-if="tempBoxShow"
      >
        <span class="temp-form-box-title">Expression</span>
        <el-form-item prop="expression">
          <el-input
            class="temp-form-box-input"
            v-model="tempBox.expression"
            size="small"
            disabled
          ></el-input>
        </el-form-item>
        <span class="temp-form-box-title" v-if="tempBox.vars.length"
          >Variable</span
        >
        <el-form-item
          v-for="(item, index) in tempBox.vars"
          :prop="item"
          :key="index"
        >
          <el-row>
            <el-col :span="7" class="temp-form-box-col">
              <el-input
                class="temp-form-box-input"
                v-model="tempBox.vars[index]"
                :id="'tempBox' + index"
                size="small"
                :disabled="true"
              ></el-input>
            </el-col>
            <el-col :span="16" v-if="format(item).key">
              <select-alert-silence
                :filter-silence="filterSilence"
                :silence-data="format(item).arr"
                :panel-lock="false"
                :placement="'bottom-start'"
                :typeContentLoading="typeContentLoading"
                @selectSilence="
                  (val) => {
                    silenceChange(val, item);
                  }
                "
                ref="selectPanel"
                style="width: 240px"
              >
                <template v-slot:header>
                  <div class="explore-select-header">
                    <el-input
                      :placeholder="$t('overall.search')"
                      clearable
                      size="mini"
                      style="width: 300px; padding: 0 10px"
                      v-model="filterSilence"
                      id="panel-list-search"
                    ></el-input>
                  </div>
                </template>

                <template v-slot:trigger>
                  <el-input
                    class="panel-name"
                    placeholder=""
                    readonly="readonly"
                    v-model="tempBox[item]"
                    size="small"
                  >
                    <span
                      slot="suffix"
                      class="
                        el-input__icon
                        el-icon-circle-close
                        el-input__clear
                      "
                      @click.stop="clearValue(item)"
                    ></span>
                  </el-input>
                </template>
              </select-alert-silence>
            </el-col>
            <el-col :span="17" v-else>
              <el-input
                v-model="tempBox[item]"
                :id="'tempBox' + item"
                size="small"
              ></el-input>
            </el-col>
          </el-row>
        </el-form-item>
      </el-form>
      <span slot="footer">
        <button
          id="temp-box-esc"
          class="nz-btn nz-btn-size-normal nz-btn-style-light"
          @click="tempBoxShowChange(false)"
        >
          <span>{{ $t("overall.cancel") }}</span>
        </button>
        <button
          id="chart-box-save"
          v-has="`expressionTemplate_add`"
          :disabled="prevent_opt.save"
          class="nz-btn nz-btn-size-normal nz-btn-style-normal"
          @click="tempBoxShowChange(true)"
        >
          <span>{{ $t("overall.save") }}</span>
        </button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
import selectAlertSilence from '../../../common/alert/selectAlertSilence'
import { get } from '@/http'
import { PromQLExtension } from '@prometheus-io/codemirror-promql'
import { baseTheme, promqlHighlighter, lightTheme } from './CMTheme.tsx'
import { newCompleteStrategy } from '@prometheus-io/codemirror-promql/dist/esm/complete'
// import {basicSetup} from '@codemirror/basic-setup';
import { EditorView, highlightSpecialChars, keymap, ViewUpdate, placeholder } from '@codemirror/view'
import { EditorState, Prec, Compartment } from '@codemirror/state'
import { bracketMatching, indentOnInput, syntaxHighlighting, syntaxTree } from '@codemirror/language'
import { defaultKeymap, history, historyKeymap, insertNewlineAndIndent } from '@codemirror/commands'
import { highlightSelectionMatches } from '@codemirror/search'
import { lintKeymap } from '@codemirror/lint'
import {
  autocompletion,
  completionKeymap,
  CompletionContext,
  CompletionResult,
  closeBrackets,
  closeBracketsKeymap
} from '@codemirror/autocomplete'
import exploreHistory from '@/components/page/dashboard/explore/histoyrComponent/exploreHistory'
import MonacoEditor from 'vue-monaco'
import logqlMixin from '@/components/page/dashboard/explore/logql/logqlMixin'
export default {
  name: 'promqlInput',
  mixins: [logqlMixin],
  components: {
    selectAlertSilence,
    exploreHistory,
    MonacoEditor
  },
  props: {
    index: { type: Number },
    pqid: {
      type: String, default: ''
    },
    expressionList: { type: Array },
    state: { type: Number },
    plugins: { type: Array },
    styleType: Number,
    historyParam: { type: Object },
    showRemove: { type: Boolean, default: true },
    projectRightBox: { type: Boolean, default: false },
    metricOptionsParent: { type: Array },
    inputId: String,
    required: {
      type: Boolean, default: false
    },
    showTemp: {
      type: Boolean,
      default: true
    },
    typeContentLoading: {
      type: Boolean,
      default: false
    },
    fromFatherData: {
      type: Boolean,
      default: false
    },
    type: {
      type: String // metric和log两种，为空时视为metric
    },
    isTopo: {
      type: Boolean,
      default: false
    }
    // metricOptions: {type: Array},
    // metricStore: {type: Array}
  },
  data () {
    return {
      oldcCodeLength: '',
      newView: null,
      codeMirrorValue: [],
      dropDownVisible: false,
      // metricStore:[],
      metricOptions: [],
      cascaderValue: '',
      errorMsg: null,
      appendMsg: null,
      firstAddEvent: true,
      tempBoxShow: false,
      tempBox: {
        expression: '',
        vars: []
      },
      tempBoxShowLoading: false,
      assetOption: [],
      moduleOption: [],
      endpointOption: [],
      datacenterOption: [],
      projectOption: [],
      filterSilence: '',
      tempBoxId: {},
      loading: false,
      firstInit: true,
      historyshow: false
    }
  },
  computed: {
    cascaderProps () {
      if (this.type === 'log') {
        return {
          lazy: true,
          lazyLoad (node, resolve) {
            const { level } = node
            if (level === 0) {
              get('/logs/loki/api/v1/labels').then(res => {
                if (res.data) {
                  const nodes = res.data.sort().map(d => ({
                    value: d,
                    label: d,
                    leaf: false
                  }))
                  resolve(nodes)
                } else {
                  resolve([])
                }
              })
            } else if (level === 1) {
              get(`/logs/loki/api/v1/label/${node.value}/values`).then(res => {
                if (res.data) {
                  const nodes = res.data.sort().map(d => ({
                    value: d,
                    label: d,
                    leaf: true
                  }))
                  resolve(nodes)
                } else {
                  resolve([])
                }
              })
            }
          }
        }
      } else {
        return { emitPath: false }
      }
    }
  },
  mounted () {
    if (!this.fromFatherData && this.type !== 'log') {
      this.queryMetrics()
    }
  },
  methods: {
    async initCodeMirror () {
      const self = this
      let baseUrl = this.$axios.defaults.baseURL
      if (!baseUrl || baseUrl == '/') {
        baseUrl = window.location.protocol + '//' + window.location.host
      }
      // let metadataOptions = await this.$get('prom/api/v1/metadata')
      // console.log(metadataOptions)
      // metadataOptions = metadataOptions.data
      // let metricsdataOptions = await this.$get('prom//api/v1/label/__name__/values')
      // console.log(metricsdataOptions)
      // metricsdataOptions = metricsdataOptions.data

      const promqlExtension = new PromQLExtension()
        .activateCompletion(true)
        .activateLinter(true)
        .setComplete({
          completeStrategy: new HistoryCompleteStrategy(
            newCompleteStrategy({
              remote: {
                url: baseUrl + '/prom/',
                fetchFn: self.fetchFn
              },
              maxMetricsMetadata: 99999
            })
          )

        })
      function HistoryCompleteStrategy (CompleteStrategy) {
        const obj = {}
        obj.complete = CompleteStrategy
        obj.queryHistory = []
        obj.promQL = function (context) {
          return Promise.resolve(this.complete.promQL(context)).then((res) => {
            const { state, pos } = context
            const tree = syntaxTree(state).resolve(pos, -1)
            const start = res != null ? res.from : tree.from

            if (start !== 0) {
              return res
            }

            const historyItems = {
              from: start,
              to: pos,
              options: this.queryHistory.map((q) => ({
                label: q.length < 80 ? q : q.slice(0, 76).concat('...'),
                detail: 'past query',
                apply: q,
                info: q.length < 80 ? undefined : q
              })),
              span: /^[a-zA-Z0-9_:]+$/
            }
            if (res !== null) {
              historyItems.options = historyItems.options.concat(res.options)
            }
            // console.log(historyItems)
            return historyItems
          })
        }
        return obj
      }
      const highlighter = syntaxHighlighting(promqlHighlighter)
      const dynamicConfigCompartment = new Compartment()
      const dynamicConfig = [
        highlighter,
        promqlExtension.asExtension(),
        lightTheme
      ]
      if (!this.newView) {
        const EditorViewstate = EditorState.create({
          doc: self.codeMirrorValue[self.index],
          extensions: [
            // basicSetup,
            baseTheme,
            highlightSpecialChars(),
            history(),
            EditorState.allowMultipleSelections.of(true),
            indentOnInput(),
            bracketMatching(),
            closeBrackets(),
            autocompletion(),
            highlightSelectionMatches(),
            EditorView.lineWrapping,
            keymap.of([...closeBracketsKeymap, ...defaultKeymap, ...historyKeymap, ...completionKeymap, ...lintKeymap]),
            placeholder('Expression (press Shift+Enter for newlines)'),
            dynamicConfigCompartment.of(dynamicConfig),
            keymap.of([
              {
                key: 'Escape',
                run: (v) => {
                  v.contentDOM.blur()
                  return false
                }
              }
            ]),
            Prec.highest(
              keymap.of([
                {
                  key: 'Enter',
                  run: (v) => {
                    self.newChange()
                    return true
                  }
                },
                {
                  key: 'Shift-Enter',
                  run: insertNewlineAndIndent
                }
              ])
            ),
            EditorView.updateListener.of((update) => {
              self.newChange(update.state.doc.toString())
            })
          ],
          editorState: {
            changeByRange: self.newChange,
            changes: self.newDoc,
            facet: self.newChange
          }
        })
        const view = new EditorView({
          state: EditorViewstate,
          // parent: document.getElementById('editor')
          parent: document.getElementById(this.pqid + 'editor' + self.index)
        })
        self.newView = view
      } else {
        const to = self.oldcCodeLength
        const from = self.oldcCodeLength
        self.newView.dispatch(
          self.newView.state.update({
            effects: dynamicConfigCompartment.reconfigure(dynamicConfig),
            changes: { from, to, insert: self.codeMirrorValue[self.index] }
          })
        )
      }
    },
    newChange (val) {
      if (this.firstInit && this.isTopo) {
        return
      }
      if (val) {
        this.oldcCodeLength = val.length
        this.codeMirrorValue[this.index] = val
        // this.expressionList[this.index] = val
        this.$set(this.expressionList, this.index, val)
        this.metricKeyDown(val)
      } else {
        this.oldcCodeLength = 0
        this.codeMirrorValue[this.index] = ''
        // this.expressionList[this.index] = ''
        this.$set(this.expressionList, this.index, '')
        this.$emit('change', '')
      }
    },
    newDoc (val) {
      // console.log('doc', val)
    },
    promqlInputChange (val) {
      if (this.type === 'metrics') {
        try {
          const text = this.newView.state.doc.toString()
          this.newView.dispatch(
            this.newView.state.update({
              changes: { from: 0, to: text.length, insert: this.codeMirrorValue[this.index] }
            })
          )
        } catch (error) {}
      }
    },
    fetchFn (a, b) {
      const params = {}
      if (b) {
        params['match[]'] = b.body.get('match[]')
        params.start = b.body.get('start')
        params.end = b.body.get('end')
        a += '?match[]=' + b.body.get('match[]')
        return fetch(a, {
          ...b,
          // body: JSON.stringify(params),
          redirect: 'follow',
          headers: {
            Authorization: localStorage.getItem('nz-token'),
            'content-type': 'application/x-www-form-urlencoded'
          }
        })
      }
      return fetch(a, {
        ...b,
        headers: {
          Authorization: localStorage.getItem('nz-token')
        }
      })
    },
    closeDropdown () {
      this.dropDownVisible = false
    },
    clearExpression: function () {
      this.expressionChange()
      this.cascaderValue = ''
    },
    enableExpression: function () {
      this.$emit('enableExpression', this.index)
    },
    addExpression: function () {
      this.$emit('addExpression', this.index)
    },
    copyExpression () {
      this.$emit('copyExpression', this.index)
    },
    removeExpression: function () {
      this.$emit('removeExpression', this.index)
    },
    toggleDropdown () {
      this.dropDownVisible = !this.dropDownVisible
      this.getMetricOptions()
    },
    getMetricOptions () {
      if (!this.metricOptions.length) {
        this.queryMetrics()
      }
    },
    queryMetrics: function () {
      this.loading = true
      this.$get('prom/api/v1/label/__name__/values').then(response => {
        if (response.status == 'success') {
          const metrics = response.data.sort()
          const metricMap = new Map()
          metrics.forEach((item) => {
            let key = ''
            if (/^[a-zA-Z_:][a-zA-Z0-9_:]*/.test(item)) {
              key = item.split(/[_:]/, 1)[0]
            } else {
              key = item
            }
            if (metricMap.get(key)) {
              const values = metricMap.get(key)
              values.push({ label: item, value: item })
            } else {
              const values = [{ label: item, value: item }]
              metricMap.set(key, values)
            }
            // this.metricStore.push({label:item,value:item,insertText:item})
          })
          for (const key of metricMap.keys()) {
            const option = {
              label: key,
              value: key
            }
            if (metricMap.get(key) && metricMap.get(key).length > 1) {
              option.children = metricMap.get(key)
            }
            this.metricOptions.push(option)
          }
          if (this.showTemp) {
            this.getExprTemp()
          }
        }
      })
    },
    filterInput: function (queryString, cb) {
      const metrics = Object.assign([], this.metricStore)
      const result = queryString
        ? metrics.filter((item) => {
          return item.value.toLowerCase().indexOf(queryString.toLowerCase()) != -1
        })
        : metrics
      cb(result)
    },
    metricChange: function (value) {
      this.expressionList[this.index] = value
      this.codeMirrorValue[this.index] = value
      this.dropDownVisible = false
      this.$emit('change', value)
      // this.initCodeMirror()
      this.$forceUpdate()
      this.cascaderValue = ''
    },
    metricChangeNew (value) {
      // console.log(value)
      if (!value) return
      this.insertText(value)
      this.dropDownVisible = false
      this.$emit('change', value)
      this.$forceUpdate()
      this.cascaderValue = ''
    },
    logLabelChange (value) {
      if (!value || value.length === 0) return
      this.expressionList[this.index] = `{${value[0]}="${value[1]}"}`
      this.codeMirrorValue[this.index] = `{${value[0]}="${value[1]}"}`
      this.dropDownVisible = false
      this.$emit('change', value)
      this.$forceUpdate()
      this.cascaderValue = ''
    },
    metricKeyDown (val) {
      if (this.required) {
        this.metricChange(val)
      }
    },
    expressionChange: function () {
      if (this.$refs.monacoEditor) {
        setTimeout(() => {
          this.heightChange()
        }, 100)
      }
      this.$emit('change')
    },
    setError: function (errMsg) {
      this.errorMsg = errMsg
    },
    getExprTemp () {
      this.$get('/expression/tmpl/gname').then(res => {
        this.loading = false
        if (res.code === 200) {
          res.data.list.forEach(item => {
            this.metricOptions.unshift({
              label: item,
              value: item,
              children: [],
              temp: true,
              child: false
            })
          })
        }
      })
    },
    lazyLoad (node, data) {
      if (data.temp) {
        if (!data.child) {
          this.tempBoxShowLoading = true
          this.$get('/expression/tmpl?pageSize=-1&gname=' + data.value).then(res => {
            this.tempBoxShowLoading = false
            if (res.code === 200) {
              res.data.list.forEach(item => {
                item.label = item.name
                item.value = false
                item.temp = true
                item.child = true
              })
              this.metricOptions.find(item => item.value === data.value).children = res.data.list

              // el-cascader-panel监听到options变化 会触发scrollIntoView函数
              const temp = this.$refs.metricSelector.scrollIntoView
              this.$refs.metricSelector.scrollIntoView = function () {}
              this.$nextTick(() => {
                this.$refs.metricSelector.scrollIntoView = temp
              })
            }
          })
        } else {
          this.dropDownVisible = false
          this.$get('/expression/tmpl/' + data.id).then(res => {
            if (res.code === 200) {
              if (!res.data.vars || !res.data.vars.length) {
                this.metricChange(data.expression)
                this.initCodeMirror()
                return
              }
              res.data.vars.forEach(item => {
                res.data[item] = ''
                const arr = item.split('.')
                const keyword = arr[0].toLowerCase()
                this.getAllOptins(keyword, keyword + 'Option')
              })
              this.tempBox = {
                ...this.tempBox,
                ...res.data
              }

              setTimeout(() => {
                this.tempBoxShow = true
              }, 100)
            }
          })
        }
      } else if (data.children && (!data.children.length || data.children.length > 100) && this.type !== 'log') {
        setTimeout(() => {
          new Promise(resolve => {
            const children = this.$store.state.metricsList.find(item => item.value === data.value).children
            resolve(children)
          }).then((children) => {
            const childrenCopy = JSON.parse(JSON.stringify(children))
            const findChild = this.metricOptions.find(item => item.label === data.label)
            if (childrenCopy.length > 100) {
              childrenCopy.splice(100, childrenCopy.length)
              childrenCopy.push({
                label: 'More',
                value: false,
                parent: data.label,
                more: true
              })
              findChild.children = childrenCopy
            } else {
              findChild.children = childrenCopy
            }
            this.metricOptions.forEach(item => {
              if (!item.temp && item.children && item.value != data.value) {
                item.children = []
              }
            })

            // el-cascader-panel监听到options变化 会触发scrollIntoView函数
            const temp = this.$refs.metricSelector.scrollIntoView
            this.$refs.metricSelector.scrollIntoView = function () {}
            this.$nextTick(() => {
              this.$refs.metricSelector.scrollIntoView = temp
            })
          })
        })
      } else if (data.more) {
        setTimeout(() => {
          new Promise(resolve => {
            const children = this.$store.state.metricsList.find(item => item.label === data.parent).children
            resolve(children)
          }).then((children) => {
            let childrenCopy = JSON.parse(JSON.stringify(children))
            const findChild = this.metricOptions.find(item => item.label === data.parent)
            if (childrenCopy.length > 100) {
              childrenCopy = childrenCopy.splice(findChild.children.length, 100)
              findChild.children.splice(findChild.children.length - 1, 1)
              findChild.children.push(...childrenCopy)
              if (findChild.children.length < children.length - 1) {
                findChild.children.push({
                  label: 'More',
                  value: false,
                  parent: data.parent,
                  more: true
                })
              } else {
                findChild.children.splice(findChild.children.length - 1, 1)
              }
            } else {
              findChild.children = childrenCopy
            }

            // el-cascader-panel监听到options变化 会触发scrollIntoView函数
            const temp = this.$refs.metricSelector.scrollIntoView
            this.$refs.metricSelector.scrollIntoView = function () {}
            this.$nextTick(() => {
              this.$refs.metricSelector.scrollIntoView = temp
            })
          })
        })
      }
    },
    tempBoxShowChange (flag) {
      this.tempBoxShow = flag
      if (flag) {
        this.cascaderValue = ''
        const params = {}
        params.expression = this.tempBox.expression
        params.varsVal = {}
        let returnFlag = false
        let errorStr = ''
        this.tempBox.vars.forEach((item) => {
          params.varsVal[item] = this.tempBoxId[item] || this.tempBox[item]
          if (!this.tempBox[item]) {
            errorStr += item + ','
            returnFlag = true
          }
        })

        if (returnFlag) {
          this.$message({
            message: this.$t('config.exprTemp.errorStr', { errorStr: errorStr }),
            type: 'error'
          })
          return
        }

        if (this.tempBox.vars.length == 0) {
          this.tempBoxShow = false
          // eslint-disable-next-line vue/no-mutating-props
          // this.expressionList[this.index] = params.expression
          this.insertText(params.expression)
          this.$emit('change', params.expression)
          return
        }

        this.$post('/expression/tmpl/render', params).then(res => {
          if (res.code === 200) {
            this.tempBoxShow = false
            // this.expressionList[this.index] = res.data.expression
            this.insertText(res.data.expression)
            this.$emit('change', res.data.expression)
          }
        })
      } else {
        this.tempBox = {}
      }
    },

    format (str) {
      const arr = str.split('.')
      const keyword = arr[0].toLowerCase()
      switch (keyword) {
        case 'asset':
        case 'module':
        case 'endpoint':
        case 'datacenter':
        case 'project':
          return {
            arr: this[keyword + 'Option'],
            key: keyword,
            value: ((keyword == 'module' || keyword == 'project' || keyword == 'datacenter') ? 'name' : 'host')
          }
        default:
          return {
            key: false
          }
      }
    },
    getAllOptins (key, arr) {
      switch (key) {
        case 'asset':
          this.$get('asset/asset', { pageNo: 1, pageSize: -1 }).then(response => {
            if (response.code == 200) {
              const arr = []
              response.data.list.forEach(asset => {
                asset.name = asset.sn
                const dcF = arr.find(dc => dc.id === asset.dc.id)
                if (dcF) {
                  dcF.children.push(asset)
                } else {
                  const dc = { ...asset.dc }
                  dc.children = [asset]
                  arr.push(dc)
                }
              })
              this.assetOption = arr
            }
          })
          break
        case 'module':
          this.$get('monitor/module/tree', { pageNo: 1, pageSize: -1 }).then(response => {
            if (response.code == 200) {
              this.moduleOption = response.data.list
            }
          })
          break
        case 'endpoint':
          this.$get('monitor/endpoint/tree', { pageNo: 1, pageSize: -1 }).then(response => {
            if (response.code == 200) {
              this.endpointOption = response.data.list
            }
          })
          break
        case 'datacenter':
          this.$get('dc', { pageNo: 1, pageSize: -1 }).then(response => {
            if (response.code == 200) {
              this.datacenterOption = response.data.list
            }
          })
          break
        case 'project':
          this.$get('monitor/project', { pageNo: 1, pageSize: -1 }).then(response => {
            if (response.code == 200) {
              this.projectOption = response.data.list
            }
          })
          break
        default:
          break
      }
    },
    silenceChange (val, key) {
      this.tempBox[key] = val.name
      this.tempBoxId[key] = val.id
    },
    clearValue (key) {
      this.tempBox[key] = ''
    },
    tempBoxClose () {
      this.cascaderValue = ''
    },
    selectHistory (str) {
      this.insertText(str)
    },
    insertText (insertTxt) {
      // 获取el-input中的input元素
      // const elInput = this.$refs.elInput.$el.firstElementChild
      // 获取el-input的值
      // const txt = elInput.value
      // 获取选区开始位置
      // const startPos = elInput.selectionStart
      // 获取选区结束位置
      // const endPos = elInput.selectionEnd
      // if (startPos === undefined || endPos === undefined) return
      // 将文本插入光标位置
      // this.expressionList[this.index] = txt.substring(0, startPos) + insertTxt + txt.substring(endPos)
      // 将光标移至文本末尾
      // elInput.focus()
      // elInput.selectionStart = startPos + insertTxt.length
      // elInput.selectionEnd = startPos + insertTxt.length
      this.expressionList[this.index] = insertTxt
      this.codeMirrorValue[this.index] = insertTxt
      this.initCodeMirror()
    },
    /* setMsg:function(){
        this.appendMsg
      } */
    prettyCode () {
      this.$nextTick(() => {
        const text = this.newView.state.doc.toString()
        this.newView.dispatch(
          this.newView.state.update({
            changes: { from: 0, to: text.length, insert: this.codeMirrorValue[this.index] }
          })
        )
      })
    },
    showHistoryBox (flag) {
      this.historyshow = flag
    }
  },
  watch: {
    dropDownVisible (n, o) {
      if (this.$refs.metricSelector) {
        this.$refs.metricSelector.dropDownVisible = n
        if (!this.expressionList[this.index] || this.expressionList[this.index] == '') {
          this.cascaderValue = ''
        }
      }
    },
    metricOptionsParent: {
      deep: true,
      immediate: true,
      handler (n, o) {
        if (n) {
          this.metricOptions = JSON.parse(JSON.stringify(n))
        }
      }
    },
    expressionList: {
      deep: true,
      immediate: true,
      handler (n, o) {
        this.codeMirrorValue[this.index] = n[this.index]
        if (this.isTopo && this.firstInit) {
          setTimeout(() => {
            const text = this.newView.state.doc.toString()
            this.newView.dispatch(
              this.newView.state.update({
                changes: { from: 0, to: text.length, insert: this.codeMirrorValue[this.index] }
              })
            )
            this.firstInit = false
          }, 200)
        }
      }
    },

    // codeMirrorValue:{
    //   deep:true,
    //   imediate:true,
    //   handler(n){
    //     if(n){
    //       this.oldcCodeLength = n.length
    //     }
    //   }
    // }
    type: {
      deep: true,
      immediate: true,
      handler (n) {
        if (n !== 'log') {
          this.$nextTick(() => {
            this.initCodeMirror()
          })
        }
      }
    }
  },
  beforeDestroy () {
    this.newView = null
  }
}
</script>
<style>
.input-box .el-input__inner {
  height: 30px;
}
.nz-temp-box /deep/ .el-dialog__body {
  padding: 10px 20px 0 20px;
}
.nz-temp-box /deep/ .el-dialog__footer {
  margin-top: 0;
}
.nz-temp-box .nz-btn-style-light {
  margin-right: 10px;
}
.nz-temp-box .nz-btn-style-normal {
  margin-left: 10px;
}
</style>
