<template>
  <el-dialog
    append-to-body
    width="480px"
    limited-area
    :title="$t(measureTitle)"
    :visible="true"
    top="5%"
    class="add-measure-modal"
    :close-on-press-escape="false"
    :close-on-click-modal="false"
    @close="handleHide(false)">
    <el-form :model="measure" class="add-measure" label-position="top" :rules="rules"  ref="measureForm">
      <el-form-item :label="$t('name')" prop="name">
        <div>
          <el-input class="measures-width measure-name-input" size="medium" v-model.trim="measure.name" :placeholder="$t('kylinLang.common.nameFormatValidTip2')"></el-input>
        </div>
      </el-form-item>
      <el-form-item :label="$t('expression')" prop="expression">
        <el-select :popper-append-to-body="false" class="measures-width measure-expression-select" popper-class="js_measure-expression" size="medium" v-model="measure.expression" @change="changeExpression">
          <el-option
            v-for="item in expressionsConfigs"
            :key="item.value"
            :label="item.label"
            :value="item.value">
          </el-option>
        </el-select>
        <template v-if="measure.expression ==='SUM_LC'">
          <div class="ksd-title-label-mini ksd-mtb-8">{{$t('semiAdditive')}}</div>
          <div class="semi-additive-desc ksd-fs-12">
            <ol>
              <li><i class="point">•</i>{{$t('semiAdditiveMsg1')}}</li>
              <li><i class="point">•</i>{{$t('semiAdditiveMsg2')}}</li>
              <li><i class="point">•</i>{{$t('semiAdditiveMsg3')}}</li>
            </ol>
          </div>
        </template>
      </el-form-item>
      <el-form-item v-if="measure.expression === 'TOP_N'|| measure.expression === 'PERCENTILE_APPROX' || measure.expression === 'COUNT_DISTINCT'" :label="$t('return_type')" >
        <el-select
          :popper-append-to-body="false"
          size="medium"
          v-model="measure.return_type"
          class="measures-width"
          @change="changeReturnType">
          <el-option
            v-for="(item, index) in getSelectDataType"
            :key="index"
            :label="item.name"
            :value="item.value">
          </el-option>
        </el-select>
      </el-form-item>
      <div class="ksd-fs-16 ksd-mb-6 value-label" v-if="measure.expression === 'TOP_N'">
        {{$t('paramValue')}}
      </div>
      <el-form-item :class="{'is-error': corrColumnError || (ccValidateError&&ccVisible), 'cc-item': ccVisible, 'corr-item': measure.expression ==='CORR'}" prop="parameterValue.value" key="parameterItem">
        <span slot="label" class="withIconLabel"><span>{{isOrderBy}}</span><el-tooltip
        effect="dark" placement="right" v-if="measure.expression ==='CORR'"><span slot="content" v-html="$t('corrTips')"></span><i class="el-ksd-icon-more_info_16 icon ksd-ml-2"></i></el-tooltip><el-tooltip
        effect="dark" placement="right" v-if="measure.expression ==='SUM_LC'"><span slot="content" v-html="$t('sumLcTips')"></span><i class="el-ksd-icon-more_info_16 icon ksd-ml-2"></i></el-tooltip>
        </span>
        <el-tag type="info" class="measures-width" v-if="measure.expression === 'SUM(constant)' || measure.expression === 'COUNT(constant)'">1</el-tag>
        <div class="measure-flex-row" v-else>
          <div class="flex-item">
            <el-select
            class="parameter-select"
            popper-class="js_parameter-select"
            :class="{
            'measures-addCC': measure.expression !== 'COUNT_DISTINCT' && measure.expression !== 'TOP_N',
            'measures-width': measure.expression === 'COUNT_DISTINCT' || measure.expression === 'TOP_N',
            'error-tip': showMutipleColumnsTip,
            'error-measure': handlerErrorTip(measure)}"
            size="medium" v-model="measure.parameterValue.value" :placeholder="$t('kylinLang.common.pleaseSelectOrSearch')"
            filterable @change="(v) => changeParamValue(v, measure)" :disabled="isEdit">
              <i slot="prefix" class="el-input__icon el-ksd-icon-search_22" v-if="!measure.parameterValue.value"></i>
              <el-option-group key="column" :label="$t('columns')">
                <el-option
                  v-for="(item, index) in getParameterValue"
                  :key="index"
                  :label="item.name"
                  :value="item.name">
                  <el-tooltip :content="item.name" effect="dark" placement="top"><span>{{item.name.split('.')[item.name.split('.').length - 1] | omit(30, '...')}}</span></el-tooltip>
                  <span class="ky-option-sub-info">{{item.datatype.toLocaleLowerCase()}}</span>
                </el-option>
              </el-option-group>
              <el-option-group key="ccolumn" :label="$t('ccolumns')" v-if="getCCGroups().length || newCCList.length">
                <el-option
                  v-for="item in getCCGroups()"
                  :key="item.guid"
                  :label="item.tableAlias + '.' + item.columnName"
                  :value="item.tableAlias + '.' + item.columnName">
                  <el-tooltip :content="`${item.tableAlias}.${item.columnName}`" effect="dark" placement="top"><span>{{item.columnName | omit(30, '...')}}</span></el-tooltip>
                  <span class="ky-option-sub-info">{{item.datatype.toLocaleLowerCase()}}</span>
                </el-option>
                <el-option
                  v-for="item in newCCList"
                  :key="item.table_guid"
                  :label="item.tableAlias + '.' + item.columnName"
                  :value="item.tableAlias + '.' + item.columnName">
                  <el-tooltip :content="`${item.tableAlias}.${item.columnName}`" effect="dark" placement="top"><span>{{item.columnName | omit(30, '...')}}</span></el-tooltip>
                  <span class="ky-option-sub-info">{{item.datatype.toLocaleLowerCase()}}</span>
                </el-option>
              </el-option-group>
            </el-select>
            <common-tip :content="$t('addCCTip')"><el-button size="medium" v-if="measure.expression !== 'COUNT_DISTINCT' && measure.expression !== 'TOP_N'" icon="el-ksd-icon-auto_computed_column_old" type="primary" plain @click="newCC" class="ksd-ml-6" :disabled="(isEdit && ccVisible) || !!isHybridModel"></el-button></common-tip>
          </div>
          <el-button type="primary" size="mini" icon="el-icon-ksd-add_2" plain circle v-if="measure.expression === 'COUNT_DISTINCT'&&measure.return_type!=='bitmap'" class="ksd-ml-10" @click="addNewProperty"></el-button>
        </div>
        <p class="sync-comment-tip" v-if="showSync">{{$t('syncCommentTip1', {comment: columnComment(measure.parameterValue.value)})}}<span class="sync-content" @click="handleSyncComment">{{$t('syncContent')}}</span></p>
      </el-form-item>
      <CCEditForm ref="ccEditForm" class="ksd-mb-8" :class="{'error-tips': corrColumnError}" key="ccEditForm" v-if="ccVisible" @checkSuccess="saveCC" @delSuccess="delCC" :hideCancel="isEditMeasure" :isEditMeasureCC="!isEdit" source="createMeasure" :ccDesc="ccObject" :modelInstance="modelInstance" @resetSubmitLoading="resetSubmitType" @saveError="resetSubmitType"></CCEditForm>
      <div class="error-tips" v-if="corrColumnError">{{$t('corrColDatatypeError')}}</div>
      <el-form-item :label="isGroupBy" v-if="(measure.expression === 'COUNT_DISTINCT' || measure.expression === 'TOP_N')&&measure.convertedColumns.length>0" prop="convertedColumns[0].value" :rules="rules.convertedColValidate" key="topNItem" :class="{'measure-column-multiple': measure.expression === 'COUNT_DISTINCT'}">
        <div class="measure-flex-row" v-for="(column, index) in measure.convertedColumns" :key="index" :class="{'ksd-mt-10': !isGroupBy || (isGroupBy && index > 0)}">
          <div class="flex-item">
            <el-select :class="['measures-width', {'error-tip': showMutipleColumnsTip || column.sameIndex}]" size="medium" v-model="column.value" :placeholder="$t('kylinLang.common.pleaseSelectOrSearch')" filterable @change="changeConColParamValue(column.value, index)">
              <i slot="prefix" class="el-input__icon el-ksd-icon-search_22" v-if="!column.value"></i>
              <el-option
                v-for="(item, index) in getParameterValue2"
                :key="index"
                :label="item.name"
                :value="item.name">
                <el-tooltip :content="item.name" effect="dark" placement="top"><span>{{item.name | omit(30, '...')}}</span></el-tooltip>
                <span class="ky-option-sub-info">{{item.datatype}}</span>
              </el-option>
              <el-option-group key="ccolumn" :label="$t('ccolumns')" v-if="measure.expression === 'TOP_N' && getCCGroups(isGroupBy).length">
                <el-option
                  v-for="item in getCCGroups(isGroupBy)"
                  :key="item.guid"
                  :label="item.tableAlias + '.' + item.columnName"
                  :value="item.tableAlias + '.' + item.columnName">
                  <el-tooltip :content="`${item.tableAlias}.${item.columnName}`" effect="dark" placement="top"><span>{{item.columnName | omit(30, '...')}}</span></el-tooltip>
                  <span class="ky-option-sub-info">{{item.datatype.toLocaleLowerCase()}}</span>
                </el-option>
              </el-option-group>
            </el-select>
            <p class="error-text" v-if="column.sameIndex">{{$t('duplicateColumns')}}</p>
          </div>
          <el-button type="primary" plain icon="el-icon-ksd-add_2" size="mini" v-if="measure.expression === 'TOP_N' && index == 0" circle @click="addNewProperty" class="ksd-ml-10"></el-button><el-button
           type="primary" icon="el-icon-minus" size="mini" circle @click="deleteProperty(index)" class="del-pro" :class="[measure.expression === 'COUNT_DISTINCT' ? 'ksd-ml-10' : 'ksd-ml-5', {'del-margin-more': measure.expression === 'TOP_N' && index > 0}]" :disabled="measure.expression === 'TOP_N' && measure.convertedColumns.length == 1"></el-button>
        </div>
      </el-form-item>
      <template v-if="measure.expression ==='CORR'">
        <el-form-item :class="{'is-error': corrColumnError || (ccValidateError&&ccVisible2), 'cc-item': ccVisible2}" prop="convertedColumns[0].value" :rules="rules.convertedColValidate" key="corrItem">
          <div>
            <el-select class="measures-addCC" size="medium" v-model="measure.convertedColumns[0].value" :placeholder="$t('kylinLang.common.pleaseSelectOrSearch')" filterable @change="(v) => changeCORRParamValue(v, measure)" :disabled="isCCEdit2">
              <i slot="prefix" class="el-input__icon el-ksd-icon-search_22" v-if="!measure.convertedColumns[0].value"></i>
              <el-option-group key="column" :label="$t('columns')">
                <el-option
                  v-for="(item, index) in getParameterValue"
                  :key="index"
                  :label="item.name"
                  :value="item.name">
                  <el-tooltip :content="item.name" effect="dark" placement="top"><span>{{item.name.split('.')[item.name.split('.').length - 1] | omit(30, '...')}}</span></el-tooltip>
                  <span class="ky-option-sub-info">{{item.datatype.toLocaleLowerCase()}}</span>
                </el-option>
              </el-option-group>
              <el-option-group key="ccolumn" :label="$t('ccolumns')" v-if="getCCGroups().length || newCCList.length">
                <el-option
                  v-for="item in getCCGroups()"
                  :key="item.guid"
                  :label="item.tableAlias + '.' + item.columnName"
                  :value="item.tableAlias + '.' + item.columnName">
                  <el-tooltip :content="`${item.tableAlias}.${item.columnName}`" effect="dark" placement="top"><span>{{item.columnName | omit(30, '...')}}</span></el-tooltip>
                  <span class="ky-option-sub-info">{{item.datatype.toLocaleLowerCase()}}</span>
                </el-option>
                <el-option
                    v-for="item in newCCList"
                    :key="item.table_guid"
                    :label="item.tableAlias + '.' + item.columnName"
                    :value="item.tableAlias + '.' + item.columnName">
                    <el-tooltip :content="`${item.tableAlias}.${item.columnName}`" effect="dark" placement="top"><span>{{item.columnName | omit(30, '...')}}</span></el-tooltip>
                    <span class="ky-option-sub-info">{{item.datatype.toLocaleLowerCase()}}</span>
                  </el-option>
              </el-option-group>
            </el-select>
            <common-tip :content="$t('addCCTip')"><el-button size="medium" icon="el-ksd-icon-auto_computed_column_old" type="primary" plain class="ksd-ml-6" @click="newCC2" :disabled="(isCCEdit2 && ccVisible2) || !!isHybridModel"></el-button></common-tip>
          </div>
        </el-form-item>
        <CCEditForm class="ksd-mb-8" :class="{'error-tips': corrColumnError}" key="corrEditForm" ref="corrEditForm" v-if="ccVisible2" @checkSuccess="saveCC2" @delSuccess="delCC2" :hideCancel="isEditMeasure" :isEditMeasureCC="!isCCEdit2" source="createMeasure" :ccDesc="ccObject2" :modelInstance="modelInstance" @resetSubmitLoading="resetSubmitType" @saveError="resetSubmitType"></CCEditForm>
        <div class="error-tips" v-if="corrColumnError">{{$t('corrColDatatypeError')}}</div>
      </template>
      <template v-if="measure.expression ==='SUM_LC'">
        <el-form-item prop="convertedColumns[0].value" :rules="rules.convertedColValidate" key="SUM_LCItem">
          <span slot="label" class="withIconLabel"><span>{{$t('timeDim')}}</span><el-tooltip
            effect="dark" placement="right"><span slot="content" v-html="$t('timeDimTips')"></span><i class="el-ksd-icon-more_info_16 icon ksd-ml-2"></i></el-tooltip>
          </span>
          <el-select class="measures-addCC" size="medium" v-model="measure.convertedColumns[0].value" :placeholder="$t('kylinLang.common.pleaseSelectOrSearch')" filterable>
            <i slot="prefix" class="el-input__icon el-ksd-icon-search_22" v-if="!measure.convertedColumns[0].value"></i>
            <el-option-group key="column" :label="$t('columns')">
              <el-option
                v-for="(item, index) in getParameterValue2"
                :key="index"
                :label="item.name"
                :value="item.name">
                 <el-tooltip :content="item.name" effect="dark" placement="top"><span>{{item.name.split('.')[item.name.split('.').length - 1] | omit(30, '...')}}</span></el-tooltip>
                <span class="ky-option-sub-info">{{item.datatype.toLocaleLowerCase()}}</span>
              </el-option>
            </el-option-group>
            <el-option-group key="ccolumn" :label="$t('ccolumns')" v-if="getCCGroups(null, true).length || newCCList.length">
              <el-option
                v-for="item in getCCGroups(null, true)"
                :key="item.guid"
                :label="item.tableAlias + '.' + item.columnName"
                :value="item.tableAlias + '.' + item.columnName">
                <el-tooltip :content="`${item.tableAlias}.${item.columnName}`" effect="dark" placement="top"><span>{{item.columnName | omit(30, '...')}}</span></el-tooltip>
                <span class="ky-option-sub-info">{{item.datatype.toLocaleLowerCase()}}</span>
              </el-option>
              <el-option
                  v-for="item in newCCList"
                  :key="item.table_guid"
                  :label="item.tableAlias + '.' + item.columnName"
                  :value="item.tableAlias + '.' + item.columnName">
                  <el-tooltip :content="`${item.tableAlias}.${item.columnName}`" effect="dark" placement="top"><span>{{item.columnName | omit(30, '...')}}</span></el-tooltip>
                  <span class="ky-option-sub-info">{{item.datatype.toLocaleLowerCase()}}</span>
                </el-option>
            </el-option-group>
          </el-select>
          <common-tip :content="$t('addCCTip')"><el-button size="medium" icon="el-ksd-icon-auto_computed_column_old" type="primary" plain class="ksd-ml-6" @click="newCC2" :disabled="(isCCEdit2 && ccVisible2) || !!isHybridModel"></el-button></common-tip>
        </el-form-item>
        <CCEditForm class="ksd-mb-8" :class="{'error-tips': corrColumnError}" key="corrEditForm" ref="corrEditForm" v-if="ccVisible2" @checkSuccess="saveCC2" @delSuccess="delCC2" :hideCancel="isEditMeasure" :isEditMeasureCC="!isCCEdit2" source="createMeasure" :ccDesc="ccObject2" :modelInstance="modelInstance" @resetSubmitLoading="resetSubmitType" @saveError="resetSubmitType"></CCEditForm>
        <el-form-item :label="$t('AggreFunc')">
          <el-input value="LastChild" disabled></el-input>
        </el-form-item>
      </template>
      <el-form-item :label="$t('comment')" prop="comment">
        <div>
          <el-input class="measures-width measure-comment-input" size="medium" v-model.trim="measure.comment" :placeholder="$t('kylinLang.common.pleaseInput')"></el-input>
        </div>
      </el-form-item>
    </el-form>
    <el-alert :title="measureError" v-if="measureError" class="ksd-mt-16" type="error" show-icon></el-alert>
    <span slot="footer" class="dialog-footer ky-no-br-space">
      <el-button plain size="medium" @click="handleHide(false)">{{$t('kylinLang.common.cancel')}}</el-button>
      <el-button type="primary" size="medium" @click="checkMeasure" :disabled="sameGroupBy()" :loading="loadingSubmit">{{$t('kylinLang.common.submit')}}</el-button>
    </span>
  </el-dialog>
</template>

<script>
import Vue from 'vue'
import { Component, Watch } from 'vue-property-decorator'
import { measuresDataType, measureSumAndTopNDataType, measurePercenDataType, measuresDateTimeDataType } from '../../../../config'
import { objectClone, sampleGuid, indexOfObjWithSomeKey, handleSuccessAsync } from '../../../../util/index'
import { measureNameRegex } from 'config'
import CCEditForm from '../ComputedColumnForm/ccform.vue'
import { mapGetters, mapActions, mapState } from 'vuex'
import $ from 'jquery'
@Component({
  props: {
    isEditMeasure: {
      type: Boolean,
      default: false
    },
    measureObj: {
      type: Object,
      default () {
        return {}
      }
    },
    modelInstance: {
      type: Object
    },
    isHybridModel: {
      type: [Boolean, String]
    }
  },
  computed: {
    ...mapGetters([
      'dimMeasNameMaxLength'
    ]),
    ...mapState({
      enableCheckName: state => state.system.enableCheckName
    })
  },
  methods: {
    // 后台接口请求
    ...mapActions({
      checkInternalMeasure: 'CHECK_INTERNAL_MEASURE'
    })
  },
  components: {
    CCEditForm
  },
  locales: {
    'en': {
      requiredName: 'The measure name is required.',
      name: 'Name',
      comment: 'Comment',
      expression: 'Function',
      return_type: 'Function Parameter',
      paramValue: 'Column',
      nameReuse: 'The name of measure can\'t be duplicated within the same model',
      requiredCCName: 'The column name is required.',
      requiredreturn_type: 'The function parameter is required.',
      requiredExpress: 'The function is required.',
      columns: 'Columns',
      ccolumns: 'Computed Columns',
      requiredParamValue: 'The column is Required.',
      addCCTip: 'Create Computed Column',
      editMeasureTitle: 'Edit Measure',
      addMeasureTitle: 'Add Measure',
      semiAdditive: 'Semi-additive(Beta)',
      semiAdditiveMsg1: 'Support Last Child semi-additive measure.For example, when a bank uses account transaction record data to count savings account balances, the normal summation is used for the non-time dimension, and for the time dimension, the value of the last record needs to be taken. Please refer to product manual for details.',
      semiAdditiveMsg2: 'Two parameters need to be set.Column 1 represents aggregation value and Column 2 represents time dimension.',
      semiAdditiveMsg3: 'When query,you need to use SUM_LC(column1,column2) function in SQL.',
      timeDim: 'Time Dimension',
      AggreFunc: 'Semi-Additive Function',
      requiredTimeColumn: 'Time Dimension is required.',
      sameColumn: 'Column has been defined as a measure by the same function',
      selectMutipleColumnsTip: 'The {expression} function supports only one column when the function parameter is {params}.',
      createCCMeasureTips: 'This column’s type is {datatype}. It couldn’t be referenced by the selected function {expression}.',
      duplicateColumns: 'Same Statement',
      noProvideDecimalType: 'PERCENTILE function does not support columns with {datatype} data type.',
      syncCommentTip1: 'This column’s comment is "{comment}", ',
      syncContent: 'sync to the comment',
      corrTips: '* The supported column data types are: bigint, integer, tinyint, smallint, decimal, double and float.<br/>* If the data type of one of the columns is decimal, the other one\'s also needs to be decimal.',
      corrColDatatypeError: 'The data type of one of the columns is decimal, the other one\'s also needs to be decimal.',
      nameValid: 'Only supports Chinese or English characters, numbers, spaces and symbol（_ -()%?.）',
      sumLcTips: 'The first column is used for aggregation and it supports all numeric data types.',
      timeDimTips: 'Time dimension supports Timestamp,INT,BIGINT, String,Varchar and Char'
    }
  }
})
export default class AddMeasure extends Vue {
  measureVisible = false
  reuseColumn = ''
  measureTitle = ''
  measure = {
    name: '',
    expression: 'SUM(column)',
    parameterValue: {type: 'column', value: '', table_guid: null},
    convertedColumns: [],
    return_type: '',
    comment: '',
    nameBackUp: ''
  }
  syncComment = false
  ccObject = null
  ccObject2 = null
  isEdit = false
  isCCEdit2 = false
  ccVisible = false
  ccVisible2 = false
  ccGroups = []
  newCCList = []
  allTableColumns = []
  topNTypes = [
    {name: 'Top 10', value: 'topn(10)'},
    {name: 'Top 100', value: 'topn(100)'},
    {name: 'Top 1000', value: 'topn(1000)'}
  ]
  distinctDataTypes = [
    {name: 'Error Rate < 9.75%', value: 'hllc(10)'},
    {name: 'Error Rate < 4.88%', value: 'hllc(12)'},
    {name: 'Error Rate < 2.44%', value: 'hllc(14)'},
    {name: 'Error Rate < 1.72%', value: 'hllc(15)'},
    {name: 'Error Rate < 1.22%', value: 'hllc(16)'},
    {name: 'Precisely', value: 'bitmap'}
  ]
  percentileTypes = [
    {name: 'percentile(100)', value: 'percentile(100)'},
    {name: 'percentile(1000)', value: 'percentile(1000)'},
    {name: 'percentile(10000)', value: 'percentile(10000)'}
  ]
  integerType = ['bigint', 'int', 'integer', 'smallint', 'tinyint']
  floatType = ['decimal', 'double', 'float']
  otherType = ['binary', 'boolean', 'char', 'date', 'string', 'timestamp', 'varchar']
  showMutipleColumnsTip = false
  ccValidateError = false
  loadingSubmit = false
  corrColumnError = false
  measureError = ''

  get expressionsConfigs () {
    if (!this.modelInstance) return []
    const config = [
      {label: 'SUM (column)', value: 'SUM(column)'},
      {label: 'SUM (constant)', value: 'SUM(constant)'},
      {label: 'SUM_LC (column1, column2)', value: 'SUM_LC'},
      {label: 'MIN', value: 'MIN'},
      {label: 'MAX', value: 'MAX'},
      {label: 'TOP_N', value: 'TOP_N'},
      {label: 'COUNT (column)', value: 'COUNT(column)'},
      // {label: 'COUNT (constant)', value: 'COUNT(constant)'}, 去除 count(constant) 函数，默认添加 count_all 度量
      {label: 'COUNT_DISTINCT', value: 'COUNT_DISTINCT'},
      {label: 'CORR (column1, column2)', value: 'CORR'},
      {label: 'PERCENTILE_APPROX', value: 'PERCENTILE_APPROX'},
      {label: 'COLLECT_SET', value: 'COLLECT_SET'}
    ]
    if (this.isHybridModel) {
      return config.filter(item => item.value !== 'CORR')
    } else {
      return config
    }
  }

  get rules () {
    return {
      name: [
        { required: true, message: this.$t('requiredName'), trigger: 'blur' },
        { validator: this.validateName, trigger: 'blur' }
      ],
      expression: [{ required: true, message: this.$t('requiredExpress'), trigger: 'change' }],
      'parameterValue.value': [
        { required: true, message: this.$t('requiredParamValue'), trigger: 'change' },
        { validator: this.checkColumn }
      ],
      convertedColValidate: [{ required: true, message: this.$t('requiredParamValue'), trigger: 'blur, change' }, { validator: this.checkColumn }]
    }
  }
  get ccRules () {
    return {
      name: [{ required: true, message: this.$t('requiredCCName'), trigger: 'blur' }],
      return_type: [{ required: true, message: this.$t('requiredreturn_type'), trigger: 'change' }],
      expression: [{ required: true, message: this.$t('requiredExpress'), trigger: 'change' }]
    }
  }
  getCCGroups (isGroupBy, isSumlc) {
    if (this.ccGroups.length) {
      if (this.measure.expression === 'SUM(column)' || (this.measure.expression === 'SUM_LC' && !isSumlc) || this.measure.expression === 'CORR') {
        return this.ccGroups.filter(it => measureSumAndTopNDataType.includes(it.datatype.toLocaleLowerCase().match(/^(\w+)\(?/)[1]))
      } else if (this.measure.expression === 'TOP_N') {
        if (isGroupBy && isGroupBy === 'Group by') {
          return this.ccGroups.filter(it => measuresDataType.includes(it.datatype.toLocaleLowerCase().match(/^(\w+)\(?/)[1]))
        } else {
          return this.ccGroups.filter(it => measureSumAndTopNDataType.includes(it.datatype.toLocaleLowerCase().match(/^(\w+)\(?/)[1]))
        }
      } else if (this.measure.expression === 'PERCENTILE_APPROX') {
        return this.ccGroups.filter(item => measurePercenDataType.includes(item.datatype.toLocaleLowerCase().match(/^(\w+)\(?/)[1]))
      } else if (this.measure.expression === 'SUM_LC' && isSumlc) {
        return this.ccGroups.filter(it => measuresDateTimeDataType.includes(it.datatype.toLocaleLowerCase().match(/^(\w+)\(?/)[1]))
      } else {
        return this.ccGroups
      }
    }
    return []
  }

  get flattenLookupTables () {
    return this.modelInstance.anti_flatten_lookups
  }

  get showSync () {
    if (!this.measure.parameterValue.value || this.ccVisible || ['SUM(constant)', 'COUNT_DISTINCT'].includes(this.measure.expression)) return false
    return this.columnComment(this.measure.parameterValue.value)
  }

  // 获取列的注释
  columnComment (value) {
    const alias = value.split('.')[0]
    const nTable = this.modelInstance.getTableByAlias(alias)
    const currentColumnInfo = nTable.columns.filter(item => item.full_colname === value)
    return currentColumnInfo.length ? currentColumnInfo[0].comment || '' : ''
  }

  sameGroupBy () {
    return this.measure.expression === 'TOP_N' && this.measure.convertedColumns.filter(it => it.sameIndex).length > 0
  }
  validateName (rule, value, callback) {
    if (!value) {
      callback(new Error(this.$t('requiredName')))
    } else if (value.length > this.dimMeasNameMaxLength) {
      callback(new Error(this.$t('kylinLang.common.nameMaxLen', {len: this.dimMeasNameMaxLength})))
    } else {
      if (!measureNameRegex.test(value)) {
        callback(new Error(this.$t('nameValid')))
      }
      if (this.modelInstance.all_measures.length) {
        let isResuse = false
        for (let i = 0; i < this.modelInstance.all_measures.length; i++) {
          /* if (this.modelInstance.all_measures[i].name.toLocaleUpperCase() === this.measure.name.toLocaleUpperCase() && this.measure.guid !== this.modelInstance.all_measures[i].guid) {
            isResuse = true
            break
          } */
          // 大小写敏感
          if (this.modelInstance.all_measures[i].name === this.measure.name && this.measure.guid !== this.modelInstance.all_measures[i].guid) {
            isResuse = true
            break
          }
        }
        if (isResuse) {
          callback(new Error(this.$t('nameReuse')))
        } else {
          callback()
        }
      } else {
        callback()
      }
    }
  }

  checkColumn (rule, value, callback) {
    // TOP_N, SUM_LC 度量无需判断列是否已经被使用过了
    // CORR 度量需要判断两个列都选择重复后报错
    if (this.measure.expression === 'TOP_N' || this.measure.expression === 'SUM_LC' || this.measure.expression === 'CORR' && (!this.measure.parameterValue.value || !this.measure.convertedColumns[0].value)) {
      callback()
      return
    }
    if (!this.modelInstance.checkSameEditMeasureColumn(this.measure)) {
      callback(new Error(this.$t('sameColumn')))
    } else {
      callback()
    }
  }
  // 取消之前的约定，不用再统一传大写
  /* upperCaseName () {
    this.measure.name = this.measure.name.toLocaleUpperCase()
  } */

  changeExpression () {
    this.measure.return_type = ''
    this.measure.parameterValue.value = ''
    this.measure.comment = ''
    this.ccVisible2 = false
    this.ccVisible = false
    this.isEdit = false
    this.isCCEdit2 = false
    this.showMutipleColumnsTip = false
    this.measureError = ''
    this.$refs['measureForm'].clearValidate('parameterValue.value')
    this.$refs['measureForm'].clearValidate('convertedColumns[0].value')
    this.corrColumnError = ''
    if (this.measure.expression === 'SUM(constant)' || this.measure.expression === 'COUNT(constant)') {
      this.measure.parameterValue.type = 'constant'
      this.measure.parameterValue.value = '1'
    } else {
      this.measure.parameterValue.type = 'column'
      this.measure.parameterValue.value = ''
    }
    if (this.measure.expression === 'COUNT_DISTINCT') {
      this.measure.return_type = 'hllc(10)'
    }
    if (this.measure.expression === 'PERCENTILE_APPROX') {
      this.measure.return_type = 'percentile(100)'
    }
    if (this.measure.expression === 'TOP_N') {
      this.measure.return_type = 'topn(100)'
    }
    if (['CORR', 'TOP_N', 'SUM_LC'].indexOf(this.measure.expression) >= 0) {
      this.measure.convertedColumns = [{type: 'column', value: '', table_guid: null}]
    } else {
      this.measure.convertedColumns = []
    }
  }

  changeReturnType () {
    this.showMutipleColumnsTip = false
    if (this.measure.expression === 'COUNT_DISTINCT') {
      this.measure.convertedColumns = []
      this.measure.parameterValue.value = ''
    }
  }

  addNewProperty () {
    const GroupBy = {type: 'column', value: '', table_guid: null}
    this.measure.convertedColumns.push(GroupBy)
  }

  deleteProperty (index) {
    this.measure.convertedColumns.splice(index, 1)
    this.checkSameGroupByColumns()
  }

  getCCObj (value) {
    const measureNamed = value.split('.')
    const alias = measureNamed[0]
    const column = measureNamed[1]
    const ccObj = this.modelInstance.getCCObj(alias, column)
    return ccObj
  }

  changeParamValue (value, measure) {
    this.$refs['measureForm'] && measure.expression === 'CORR' && this.$refs['measureForm'].clearValidate('convertedColumns[0].value')
    const alias = value.split('.')[0]
    const nTable = this.modelInstance.getTableByAlias(alias)
    measure.parameterValue.table_guid = nTable && nTable.guid
    // const currentColumnInfo = nTable.columns.filter(item => item.full_colname === value)
    const ccObj = this.getCCObj(value)
    if (ccObj) {
      this.ccObject = ccObj
      this.ccVisible = true
      this.isEdit = false
    } else {
      this.ccVisible = false
      this.isEdit = false
    }
    // measure.comment = currentColumnInfo.length ? currentColumnInfo[0].comment || '' : ''
    measure.expression === 'SUM(column)' && (measure.return_type = '')
    this.syncComment = false
    this.corrColumnError = false
    this.measureError = ''
    this.$nextTick(() => {
      this.$refs['measureForm'] && measure.expression === 'CORR' && measure.convertedColumns[0].value && this.$refs['measureForm'].validateField('convertedColumns[0].value')
    })
  }

  changeConColParamValue (value, index) {
    const alias = value.split('.')[0]
    const nTable = this.modelInstance.getTableByAlias(alias)
    this.measure.convertedColumns[index].table_guid = nTable && nTable.guid
    this.checkSameGroupByColumns()
  }

  changeCORRParamValue (value, measure) {
    this.$refs['measureForm'] && this.$refs['measureForm'].clearValidate('parameterValue.value')
    const alias = value.split('.')[0]
    const nTable = this.modelInstance.getTableByAlias(alias)
    measure.convertedColumns[0].table_guid = nTable && nTable.guid
    const ccObj = this.getCCObj(value)
    if (ccObj) {
      this.ccObject2 = ccObj
      this.ccVisible2 = true
      this.isCCEdit2 = false
    } else {
      this.ccVisible2 = false
      this.isCCEdit2 = false
    }
    this.corrColumnError = false
    this.measureError = ''
    this.$nextTick(() => {
      this.$refs['measureForm'] && this.$refs['measureForm'].validateField('parameterValue.value')
    })
  }

  checkSameGroupByColumns () {
    if (this.measure.expression === 'TOP_N') {
      const columnList = this.measure.convertedColumns.map(it => it.value)
      this.measure.convertedColumns.forEach((item, index, self) => {
        item.sameIndex = columnList.indexOf(item.value) !== columnList.lastIndexOf(item.value)
      })
    }
  }

  resetCCVisble () {
    this.isEdit = false
    this.isCCEdit2 = false
    this.ccVisible = false
    this.ccVisible2 = false
    this.ccObject = null
    this.ccObject2 = null
    this.ccValidateError = false
    this.corrColumnError = false
  }

  newCC () {
    this.resetCCVisble()
    this.measure.parameterValue.value = ''
    this.measure.return_type = ''
    this.isEdit = true
    this.ccVisible = true
  }
  newCC2 () {
    this.resetCCVisble()
    this.measure.convertedColumns[0].value = ''
    this.isCCEdit2 = true
    this.ccVisible2 = true
  }
  saveCC (cc) {
    this.ccObject = cc
    this.measure.parameterValue.value = cc.tableAlias + '.' + cc.columnName
    // this.isEdit = false
    this.checkNewCC(cc, 'ccEditForm')
  }
  saveCC2 (cc) {
    this.measure.convertedColumns[0].value = cc.tableAlias + '.' + cc.columnName
    this.ccObject2 = cc
    // this.isCCEdit2 = false
    this.checkNewCC(cc, 'corrEditForm')
  }
  checkNewCC (cc, ref) {
    this.$nextTick(() => {
      if (!measureSumAndTopNDataType.includes(cc.datatype.match(/^(\w+)\(?/)[1].toLocaleLowerCase()) && (['SUM(column)', 'CORR'].includes(this.measure.expression))) {
        this.$refs[ref] && (this.$refs[ref].isEdit = true)
        this.$refs[ref] && (this.$refs[ref].errorMsg = this.$t('createCCMeasureTips', {expression: this.measure.expression, datatype: cc.datatype}))
        this.ccValidateError = true
      } else if (!measurePercenDataType.includes(cc.datatype.toLocaleLowerCase()) && this.measure.expression === 'PERCENTILE_APPROX') {
        this.$refs[ref] && (this.$refs[ref].isEdit = true)
        this.$refs[ref] && (this.$refs[ref].errorMsg = this.$t('noProvideDecimalType', {datatype: cc.datatype.match(/^(\w+)\(?/)[1].toLocaleLowerCase()}))
        this.ccValidateError = true
      } else {
        this.$refs[ref] && (this.$refs[ref].isEdit = false)
        this.ccValidateError = false
      }
      if (!this.ccValidateError) {
        cc.name = cc.tableAlias + '.' + cc.columnName
        const index = indexOfObjWithSomeKey(this.newCCList, 'name', cc.name)
        index === -1 && this.newCCList.push(cc)
      }
    })
  }
  delCC (cc) {
    this.measure.parameterValue.value = ''
    this.ccVisible = false
    this.isEdit = false
    this.corrColumnError = false
  }
  delCC2 (cc) {
    this.measure.convertedColumns[0].value = ''
    this.ccVisible2 = false
    this.isCCEdit2 = false
    this.corrColumnError = false
  }

  get isOrderBy () {
    if (this.measure.expression === 'TOP_N') {
      return 'Order/ Sum by'
    } else {
      return this.$t('paramValue')
    }
  }

  get isGroupBy () {
    if (this.measure.expression === 'TOP_N') {
      return 'Group by'
    } else {
      return ''
    }
  }
  get getSelectDataType () {
    if (this.measure.expression === 'TOP_N') {
      return this.topNTypes
    }
    if (this.measure.expression === 'COUNT_DISTINCT') {
      return this.distinctDataTypes
    }
    if (this.measure.expression === 'PERCENTILE_APPROX') {
      return this.percentileTypes
    }
  }

  get getParameterValue () {
    let targetColumns = []
    let filterType = []
    if (this.allTableColumns) {
      if (['SUM(column)', 'SUM_LC', 'TOP_N', 'CORR'].includes(this.measure.expression)) {
        filterType = measureSumAndTopNDataType
      } else if (this.measure.expression === 'PERCENTILE_APPROX') {
        filterType = measurePercenDataType
      } else {
        filterType = measuresDataType
      }
      $.each(this.allTableColumns, (index, column) => {
        const returnRegex = new RegExp('(\\w+)(?:\\((\\w+?)(?:\\,(\\w+?))?\\))?')
        const returnValue = returnRegex.exec(column.datatype)
        if (filterType.indexOf(returnValue[1]) >= 0 && !this.flattenLookupTables.includes(column.table_alias)) {
          const columnObj = {name: column.table_alias + '.' + column.name, datatype: column.datatype}
          targetColumns.push(columnObj)
        }
      })
    }
    return targetColumns
  }

  // 支持measure的任意类型
  get getParameterValue2 () {
    let targetColumns = []
    let filterType = measuresDataType
    if (this.measure.expression === 'SUM_LC') {
      filterType = measuresDateTimeDataType
    }
    $.each(this.allTableColumns, (index, column) => {
      const returnRegex = new RegExp('(\\w+)(?:\\((\\w+?)(?:\\,(\\w+?))?\\))?')
      const returnValue = returnRegex.exec(column.datatype)
      if (filterType.indexOf(returnValue[1]) >= 0 && !this.flattenLookupTables.includes(column.table_alias)) {
        const columnObj = {name: column.table_alias + '.' + column.name, datatype: column.datatype}
        targetColumns.push(columnObj)
      }
    })
    return targetColumns
  }

  handleHide (isSubmit, measure, isEdit, fromSearch) {
    this.measureVisible = false
    this.ccValidateError = false
    this.loadingSubmit = false
    this.newCCList = []
    this.$emit('closeAddMeasureDia', {
      isEdit: isEdit,
      fromSearch: fromSearch,
      data: measure,
      isSubmit: isSubmit
    })
    this.$refs['measureForm'].resetFields()
  }

  saveCCColumn () {
    this.newCCList.forEach(c => {
      this.modelInstance.addCC(c)
    })
  }

  async checkInterMea (measure, cclist) {
    this.measureError = ''
    return this.modelInstance.generateMetadata().then(async (data) => {
      try {
        // 新建measure的模型功校验measure接口使用
        let resData = objectClone(data)
        if (!this.isEditMeasure) {
          resData.simplified_measures.push(measure)
        } else {
          const name = this.measureObj.name
          const index = resData.simplified_measures.findIndex(it => it.name === name)
          index >= 0 && (resData.simplified_measures.splice(index, 1, measure))
        }
        cclist.length > 0 && (resData.computed_columns = [...resData.computed_columns, ...cclist])
        const res = await this.checkInternalMeasure(resData)
        const checkRespData = await handleSuccessAsync(res)
        return checkRespData
      } catch (res) {
        this.measureError = res.data.msg
        return false
      }
    })
  }

  async checkMeasure () {
    try {
      this.loadingSubmit = true
      // 创建measure 和 cc 整合，提交的时候统一检测 cc 是否符合规范，不再分看执行
      // if (this.ccVisible && this.isEdit) {
      //   // this.$refs.ccEditForm && await this.$refs.ccEditForm.addCC()
      //   if (this.ccValidateError) {
      //     this.loadingSubmit = false
      //     return
      //   }
      // }
      this.$refs.measureForm.validate(async (valid) => {
        if (valid) {
          // 老数据有多列但函数参数仅支持单列，此时提示错误信息
          let message = ''
          this.loadingSubmit = false
          if (this.measure.expression === 'COUNT_DISTINCT' && this.measure.return_type === 'bitmap' && this.measure.convertedColumns.length) {
            this.showMutipleColumnsTip = true
            message = this.$t('selectMutipleColumnsTip', {expression: this.measure.expression, params: 'Precisely'})
          }
          if (this.showMutipleColumnsTip) {
            this.$message({
              type: 'error',
              message
            })
            return
          }
          this.corrColumnError = false
          if (this.measure.expression === 'CORR') {
            const corr1Datatype = this.getDatatype(this.measure.parameterValue.value).toLocaleLowerCase().indexOf('decimal') >= 0
            const corr2Datatype = this.getDatatype(this.measure.convertedColumns[0].value).toLocaleLowerCase().indexOf('decimal') >= 0
            if ((corr1Datatype && !corr2Datatype) || (!corr1Datatype && corr2Datatype)) {
              this.corrColumnError = true
              return
            }
          }
          const measureClone = objectClone(this.measure)
          // 判断该操作是否属于搜索入口进来
          let isFromSearchAciton = measureClone.fromSearch
          if (measureClone.expression.indexOf('SUM(') !== -1) {
            measureClone.expression = 'SUM'
          }
          if (measureClone.expression.indexOf('COUNT(constant)') !== -1 || measureClone.expression.indexOf('COUNT(column)') !== -1) {
            measureClone.expression = 'COUNT'
          }
          measureClone.convertedColumns.unshift(measureClone.parameterValue)
          measureClone.parameter_value = measureClone.convertedColumns
          delete measureClone.parameterValue
          delete measureClone.convertedColumns
          delete measureClone.fromSearch
          if (!this.isEditMeasure && measureClone.expression === 'SUM') {
            const name = measureClone.parameter_value.length ? measureClone.parameter_value[0].value : ''
            if (name) {
              const currentMeasure = [...this.allTableColumns, ...this.ccGroups].filter(it => it.full_colname === name)
              if (currentMeasure.length && !measureSumAndTopNDataType.includes(currentMeasure[0].datatype.match(/^(\w+)\(?/)[1].toLocaleLowerCase())) {
                this.$message({ type: 'error', closeOtherMessages: true, message: this.$t('createCCMeasureTips', {expression: measureClone.expression, datatype: currentMeasure[0].datatype}) })
                return
              }
            }
          }
          // await this.checkInterMea(measureClone, this.newCCList)
          if (this.measureError) {
            return
          }
          this.saveCCColumn()
          let action = this.isEditMeasure ? 'editMeasure' : 'addMeasure'
          this.modelInstance[action](measureClone).then(() => {
            // this.resetMeasure()
            this.handleHide(true, measureClone, this.isEditMeasure, isFromSearchAciton)
          })
        } else {
          this.loadingSubmit = false
        }
      })
    } catch (e) {
      this.loadingSubmit = false
    }
  }

  getDatatype (colName) {
    const columns = [...this.getParameterValue, ...this.getCCGroups(), ...this.newCCList]
    const index = indexOfObjWithSomeKey(columns, 'name', colName)
    if (index >= 0) {
      return columns[index].datatype
    }
  }

  resetSubmitType () {
    this.loadingSubmit = false
  }

  resetMeasure () {
    this.measure = {
      name: '',
      expression: 'SUM(column)',
      parameterValue: {type: 'column', value: '', table_guid: null},
      convertedColumns: [],
      return_type: '',
      comment: '',
      nameBackUp: ''
    }
    this.syncComment = false
    this.ccVisible = false
    this.isEdit = false
    this.ccVisible2 = false
    this.isCCEdit2 = false
    this.showMutipleColumnsTip = false
    this.measureError = ''
  }

  initExpression () {
    let measureObj = objectClone(this.measureObj)
    if (measureObj.parameter_value && measureObj.parameter_value.length) {
      measureObj.parameterValue = measureObj.parameter_value[0]
      measureObj.convertedColumns = measureObj.parameter_value.length > 1 ? measureObj.parameter_value.splice(1, measureObj.parameter_value.length - 1) : []
      delete measureObj.parameter_value
      if (measureObj.parameterValue.type === 'column') {
        this.changeParamValue(measureObj.parameterValue.value, measureObj)
      }
      if (measureObj.expression === 'CORR' && measureObj.convertedColumns.length) {
        this.changeCORRParamValue(measureObj.convertedColumns[0].value, measureObj)
      }
    }
    if (measureObj.expression === 'SUM' || measureObj.expression === 'COUNT') {
      measureObj.expression = `${measureObj.expression}(${measureObj.parameterValue.type})`
    }
    this.measure = { ...measureObj }
    if (!this.isEditMeasure) {
      this.measure.guid = sampleGuid()
    }
  }

  created () {
    this.measureTitle = this.isEditMeasure ? 'editMeasureTitle' : 'addMeasureTitle'
    this.allTableColumns = this.modelInstance && this.modelInstance.getTableColumns()
    this.ccGroups = this.modelInstance.computed_columns.map(c => {
      c.name = c.tableAlias + '.' + c.columnName
      c.full_colname = c.tableAlias + '.' + c.columnName
      return c
    })
    this.initExpression()
  }

  // @Watch('isShow')
  // onShowChange (val) {
  //   this.measureVisible = val
  //   if (this.measureVisible) {
  //     this.measureTitle = this.isEditMeasure ? 'editMeasureTitle' : 'addMeasureTitle'
  //     this.allTableColumns = this.modelInstance && this.modelInstance.getTableColumns()
  //     this.ccGroups = this.modelInstance.computed_columns.map(c => {
  //       c.name = c.tableAlias + '.' + c.columnName
  //       return c
  //     })
  //     this.initExpression()
  //   } else {
  //     this.resetMeasure()
  //   }
  // }

  @Watch('measure.convertedColumns')
  onConvertedColumnsChange (val) {
    if (this.measure.expression === 'COUNT_DISTINCT' && this.measure.return_type === 'bitmap' && !val.length) {
      this.showMutipleColumnsTip = false
    }
  }

  // SUM 或 PERCENTILE_APPROX 度量不适用 varchar 列
  handlerErrorTip (m) {
    return (m.expression.indexOf('SUM') >= 0 || m.expression === 'PERCENTILE_APPROX') && m.return_type && m.return_type.indexOf('varchar') >= 0
  }

  handleSyncComment () {
    // if (!this.measure.parameterValue.table_guid) return
    // const expr = this.measure.expression.replace(/\(\w+\)$/, '')
    // if (!this.syncComment) {
    this.$set(this.measure, 'comment', this.columnComment(this.measure.parameterValue.value))
    // this.measure.comment = this.columnComment(this.measure.parameterValue.value)
    //   this.measure.nameBackUp = this.measure.name
    //   this.measure.name = `${this.measure.comment.slice(0, 100)}${expr.toLocaleUpperCase() === 'SUM' ? '' : '_' + expr}`
    // }
    // else {
    //   this.measure.name = this.measure.nameBackUp
    // }
    // this.syncComment = !this.syncComment
  }
}
</script>

<style lang="less">
  @import '../../../../assets/styles/variables.less';
  .add-measure-modal {
    .el-dialog {
      width: 500px\0 !important;
    }
  }
  .add-measure {
    .semi-additive-desc {
      background: @ke-background-color-base-1;
      padding: 10px;
      box-sizing: border-box;
      line-height: 1.2;
      .point {
        margin-right: 5px;
      }
    }
    .el-form-item.cc-item,
    .el-form-item.is-error {
      margin-bottom: 8px;
    }
    .corr-item {
      margin-bottom: 16px;
    }
    .error-tips {
      color: @ke-color-danger;
      font-size: 12px;
      margin-bottom: 24px;
    }
    .measure-flex-row {
      display: flex;
      align-items: flex-start;
      .flex-item {
        flex-shrink: 1;
        width: 100%;
        .error-tip {
          input {
            border: 1px solid @error-color-1;
          }
        }
      }
      .error-text {
        font-size: 12px;
        color: @error-color-1;
        line-height: 1;
      }
      .el-button {
        margin-top: 5px;
      }
    }
    .tip_box {
      position: relative;
      bottom: 2px;
    }
    .sync-comment-tip {
      word-break: break-all;
    }
    .sync-content {
      color: @base-color;
      cursor: pointer;
    }
    .error-measure {
      .el-input__inner {
        border: 1px solid @error-color-1;
      }
    }
    .measures-width {
      width: 100%;
    }
    .measures-addCC {
      width: 379px;
    }
    .del-margin-more {
      margin-left: 37px !important;
    }
    .value-label {
      color: @text-title-color;
    }
    .el-button.is-disabled,
    .el-button--primary.is-plain.is-disabled {
      background-color: @grey-4;
      color: @line-border-color;
      .el-icon-minus {
        cursor: not-allowed;
      }
      :hover {
        background-color: @grey-4;
        color: @line-border-color;
      }
    }
    .measure-column-multiple {
      margin-top: -10px;
    }
  }
  .el-select-group__wrap {
    .el-select-dropdown__item {
      padding-left: 10px;
    }
    .el-select-group__title {
      padding-left: 10px;
    }
    &:not(:last-child) {
      &::after {
        left: 10px;
        right: 10px;
      }
    }
  }
</style>
