<template>
    <div class="info-search">
        <info-drawer
            v-if="isShowDrawer"
            :title="$t('advancedSearch')"
            :operates="operates"
            :isShowDrawer="isShowDrawer"
            @closeDrawer="closeDrawer"
        >
            <info-form
                ref="refForm"
                class="search-main"
                :config="config"
                :modelData="parameter"
            >
                <template #fieldGroup>
                    <fieldGroup
                        :searchList="searchList"
                        :columnI18n="columnI18n"
                        :modelData="parameter.fieldGroup"
                        @pullSql="pullSql"
                    />
                </template>
            </info-form>
        </info-drawer>

        <info-dialog
            :options="templateDialog"
            @closeDialog="closeTemplate"
            @confirmDialog="saveTemplate"
        >
            <info-form
                ref="refTemplate"
                :config="templateConfig"
                :modelData="modelData"
            />
        </info-dialog>
    </div>
</template>
<script lang="ts" setup>
import { reactive, ref, computed, nextTick } from 'vue'
import fieldGroup from './fieldGroup/fieldGroup.vue'
import infoForm from '../infoForm/infoForm.vue'
import infoDialog from '../infoDialog/index.vue'
import infoDrawer from '../infoDrawer/index.vue'
import { IFieldGroup, IField } from './index'
import { deepCopy, serverApi } from '../../script'
import api from '../../api/index'
import { uniqueId } from 'lodash-es'

const props = defineProps({
    columns: {
        type: Array,
        required: true,
        default: () => {}
    },
    columnI18n: {
        type: Boolean,
        default: true
    }
})
const emit = defineEmits(['search'])

/* data */
const routeName = location.pathname
const isShowDrawer = ref(false)
const operates = { // 高级搜索配置
    size: '800px',
    wrapperClosable: false,
    closeOnPressEscape: false,
    appendToBody: true,
    title: 'advancedSearch',
    operation: [{
        label: () => 'saveTemplate',
        type: 'primary',
        i18n: true,
        plain: true,
        loading: () => false,
        method: () => {
            refForm.value.validate((valid: boolean) => {
                if (valid) {
                    templateDialog.isShowDialog = true
                    modelData.name = parameter.templateName
                }
            })
        }
    }, {
        label: () => 'confirm',
        type: 'primary',
        i18n: true,
        plain: true,
        loading: () => false,
        method: () => {
            refForm.value.validate((valid: boolean) => {
                if (valid) {
                    confirmDrawer()
                }
            })
        }
    }, {
        label: () => 'cancel',
        type: 'info',
        i18n: true,
        plain: true,
        loading: () => false,
        method: () => {
            closeDrawer()
        }
    }]
}
const config = {
    ref: 'search',
    validate: {},
    labelWidth: '100px',
    labelPosition: 'top',
    rule: [
        {
            label: '',
            inline: true,
            type: 'infoCustomSelect',
            model: 'templateName',
            placeholder: () => 'selectTemplate',
            options: () => templateList,
            optionsLabel: 'name',
            optionsValue: 'name',
            i18n: true,
            methods: (v, item) => {
                if (item) {
                    const fieldGroup = JSON.parse(item.fieldGroup)
                    formatFieldGroup(fieldGroup)
                    parameter.fieldGroup = fieldGroup
                    pullSql()
                }
            },
            style: {
                marginLeft: '100px'
            }
        },
        {
            label: 'conditionList',
            labelI18n: true,
            type: 'infoSlot',
            slotName: 'fieldGroup',
            tips: () => 'conditionGroupTips',
            tipsI18n: false,
            style: {
                marginTop: '-42px'
            }
        },
        {
            label: 'sqlSubClause',
            labelI18n: true,
            type: 'infoInput',
            inputType: 'textarea',
            minRow: 3,
            model: 'where',
            placeholder: () => 'autoGenerateSqlSubClause',
            disabled: () => true,
            style: {
                marginTop: '-10px'
            }
        }
    ]
}
const parameter = reactive({
    templateName: '',
    where: '',
    fieldGroup: {
        type: 'FieldGroup',
        group: true,
        andOr: 'AND',
        fields: [
            {
                key: '',
                type: 'Field',
                group: false,
                andOr: 'AND',
                oper: '',
                name: '',
                value: ''
            }
        ]
    }
})
const templateDialog = reactive({ // 模板
    title: 'saveTemplate',
    isShowDialog: false,
    isShowBtn: true,
    loading: {
        isLoading: false
    }
})
const templateConfig = {
    ref: 'template',
    validate: {
        name: [
            { required: true, message: 'pleaseInputTemplateName' },
            { max: 20, message: 'templateNameMaxLength' }
        ]
    },
    labelWidth: '100px',
    rule: [
        {
            label: 'templateName',
            labelI18n: true,
            type: 'infoInput',
            model: 'name'
        }
    ]
}
const modelData = reactive({
    name: '' // 保存模板名称
})

let templateList:any[] = reactive([])
const refForm = ref()
const refTemplate = ref()

/* computed */
// 搜索条件
const searchList = computed(() => {
    return props.columns.filter((column:any) => column.filters !== false)
})

/* methods */
// 打开抽屉
const showDrawer = (group?:IFieldGroup) => {
    // 初始化
    parameter.fieldGroup = {
        type: 'FieldGroup',
        group: true,
        andOr: 'AND',
        fields: [
            {
                type: 'Field',
                group: false,
                key: 'default', // 固定key
                andOr: 'AND',
                oper: '',
                name: '',
                value: ''
            }
        ]
    }
    if (group && group.fields?.length > 0) {
        const fieldGroup = deepCopy(group)
        formatFieldGroup(fieldGroup)
        parameter.fieldGroup = fieldGroup
        setTimeout(pullSql)
    }
    isShowDrawer.value = true
    getTemplates()
}
// 搜索确定
const confirmDrawer = () => {
    const fieldGroup = deepCopy(parameter.fieldGroup)
    if (fieldGroup.fields.length) {
        resetFieldGroup(fieldGroup)
        emit('search', fieldGroup)
    } else {
        emit('search')
    }
    closeDrawer()
}

// 搜索取消
const closeDrawer = () => {
    refForm.value.resetFields()
    isShowDrawer.value = false
}
/**
 * 处理value格式
 * 过滤空值
 * @param {*} group FieldGroup
 */
const resetFieldGroup = (group:IFieldGroup) => {
    // value: []
    for (let field of group.fields) {
        if (field.type === 'Field') {
            resetField(field as IField)
        } else { // FieldGroup
            resetFieldGroup(field as IFieldGroup)
        }
    }
}
const resetField = (field:IField) => {
    if (field.queryFeature) { // 转换后即重置原配置项的拷贝
        resetQueryFeature(field)
        return
    }
    let value = field.value
    if (Object.prototype.toString.call(value) !== '[object Array]') {
        if (field.oper.endsWith('LIKE')) {
            value = `%${value}%`
        }
        field.value = [value as string]
    }
}
const resetQueryFeature = (field:IField) => {
    let tempField:IField = {
        type: 'Field',
        group: false,
        andOr: field.andOr,
        name: 'queryFeature',
        oper: 'LIKE',
        value: [],
        key: field.key,
        queryFeature: deepCopy(field)
    }
    tempField.oper = field.oper.startsWith('NOT') ? 'NOT_LIKE' : 'LIKE' // field.oper 如[NOT_LIKE, NOT_EQUAL, NOT_IN]
    if (field.value === '' && field.oper.endsWith('EQUAL')) { // EQUAL空值特殊
        let transOper = {
            'NOT_EQUAL': 'LIKE',
            'EQUAL': 'NOT_LIKE'
        }
        tempField.oper = transOper[field.oper]
        field.value = '%%'
    }
    if (['IN', 'NOT_IN'].includes(field.oper)) {
        const tempGroup:IFieldGroup = {
            key: '',
            type: 'FieldGroup',
            group: true,
            andOr: field.andOr,
            fields: [],
            queryFeature: deepCopy(field)
        }
        tempField.andOr = field.oper === 'IN' ? 'OR' : 'AND'
        for (let [index, value] of (field.value as string[]).entries()) {
            tempField.value = [`%\${${field.name}:${value}}%`]
            tempGroup.fields[index] = deepCopy(tempField)
        }
        // @ts-ignore
        delete field.name
        // @ts-ignore
        delete field.oper
        // @ts-ignore
        delete field.value
        Object.assign(field, tempGroup)
    } else { // LIKE EQUAL系列
        let tempValue = field.oper.endsWith('LIKE') ? `%\${${field.name}:%${field.value}%}%` : `%\${${field.name}:${field.value}}%`
        tempField.value = [tempValue]
        Object.assign(field, tempField)
    }
}
/**
 * 格式化 field.value
 * @param {*} group
 */
const formatFieldGroup = (group:IFieldGroup) => {
    for (let field of group.fields) {
        if (field.queryFeature?.name) {
            field.key = uniqueId('field_')
            Object.assign(field, field.queryFeature)
            continue
        }
        if (field.type === 'Field') {
            field.key = uniqueId('field_')
            formatField(field as IField)
        } else { // FieldGroup
            field.key = uniqueId('group_')
            formatFieldGroup(field as IFieldGroup)
        }
    }
}
const formatField = (field:IField) => {
    const arrayOper = ['IN', 'NOT_IN', 'BETWEEN', 'NOT_BETWEEN']
    const likeOper = ['LIKE', 'NOT_LIKE']
    if (!arrayOper.includes(field.oper)) {
        field.value = field.value[0] as string
    }
    if (likeOper.includes(field.oper)) {
        field.value = (field.value as string).substring(1, field.value.length - 1)
    }
}
// FieldGroup生成sql
const pullSql = async () => {
    if (!parameter.fieldGroup.fields.length) {
        parameter.where = ''
        return
    }
    await nextTick()
    refForm.value.validate((valid: boolean) => {
        if (valid) {
            const fieldGroup = deepCopy(parameter.fieldGroup)
            resetFieldGroup(fieldGroup)
            serverApi({
                params: fieldGroup,
                interface: api.getWhereByFieldGroup,
                success: (resp) => {
                    parameter.where = resp.content !== undefined ? resp.content : resp
                }
            })
        }
    })
}
// 查询模板
const getTemplates = () => {
    templateList.splice(0)
    serverApi({
        params: { routeName: routeName },
        interface: api.getConditionByRouteName,
        success: (resp) => {
            templateList = [...resp]
        }
    })
}
// 保存模板
const saveTemplate = () => {
    refTemplate.value.validate((valid, invalidFields) => {
        if (valid) {
            const fieldGroup = deepCopy(parameter.fieldGroup)
            resetFieldGroup(fieldGroup)
            serverApi({
                params: {
                    name: modelData.name,
                    fieldGroup: JSON.stringify(fieldGroup),
                    routeName: routeName
                },
                loading: templateDialog.loading,
                interface: api.saveCondition,
                success: (resp) => {
                    closeTemplate()
                    getTemplates()
                }
            })
        }
    })
}
// 模板取消
const closeTemplate = () => {
    templateDialog.isShowDialog = false
    modelData.name = ''
}

/* 暴露属性方法 */
defineExpose({ showDrawer })
</script>
<style lang="scss" scoped>
.search-main {
    padding-left: 0;
}
</style>
