<script setup>
import { computed, nextTick, reactive } from 'vue'
import { debounce, isEmpty, trim } from 'lodash'
import { NButton, NInput } from 'naive-ui'
import IconButton from '@/components/common/IconButton.vue'
import SpellCheck from '@/components/icons/SpellCheck.vue'

const props = defineProps({
    fullSearchIcon: {
        type: [String, Object],
        default: null,
    },
    debounceWait: {
        type: Number,
        default: 500,
    },
    small: {
        type: Boolean,
        default: false,
    },
    useGlob: {
        type: Boolean,
        default: false,
    },
    exact: {
        type: Boolean,
        default: false,
    },
})

const emit = defineEmits(['filterChanged', 'matchChanged', 'exactChanged'])

/**
 *
 * @type {UnwrapNestedRefs<{filter: string, match: string, exact: boolean}>}
 */
const inputData = reactive({
    match: '',
    filter: '',
    exact: false,
})

const hasMatch = computed(() => {
    return !isEmpty(trim(inputData.match))
})

const hasFilter = computed(() => {
    return !isEmpty(trim(inputData.filter))
})

const onExactChecked = () => {
    // update search search result
    if (hasMatch.value) {
        nextTick(() => onForceFullSearch())
    }
}

const onFullSearch = () => {
    inputData.filter = trim(inputData.filter)
    if (!isEmpty(inputData.filter)) {
        inputData.match = inputData.filter
        inputData.filter = ''
        emit('matchChanged', inputData.match, inputData.filter, inputData.exact)
    }
}

const onForceFullSearch = () => {
    inputData.filter = trim(inputData.filter)
    emit('matchChanged', inputData.match, inputData.filter, inputData.exact)
}

const _onInput = () => {
    emit('filterChanged', inputData.filter, inputData.exact)
}
const onInput = debounce(_onInput, props.debounceWait, { leading: true, trailing: true })

const onClearFilter = () => {
    inputData.filter = ''
    onClearMatch()
}

const onUpdateMatch = () => {
    inputData.filter = inputData.match
    onClearMatch()
}

const onClearMatch = () => {
    const changed = !isEmpty(inputData.match)
    inputData.match = ''
    if (changed) {
        emit('matchChanged', inputData.match, inputData.filter, inputData.exact)
    } else {
        emit('filterChanged', inputData.filter, inputData.exact)
    }
}

defineExpose({
    reset: onClearFilter,
})
</script>

<template>
    <n-input-group style="overflow: hidden">
        <slot name="prepend" />
        <n-input
            v-model:value="inputData.filter"
            :placeholder="$t('interface.filter')"
            :size="props.small ? 'small' : ''"
            :theme-overrides="{ paddingSmall: '0 3px', paddingMedium: '0 6px' }"
            clearable
            @clear="onClearFilter"
            @input="onInput"
            @keyup.enter="onFullSearch">
            <template #prefix>
                <slot name="prefix" />
                <n-tooltip v-if="hasMatch" placement="bottom">
                    <template #trigger>
                        <n-tag closable size="small" @close="onClearMatch" @dblclick="onUpdateMatch">
                            {{ inputData.match }}
                        </n-tag>
                    </template>
                    {{
                        $t('interface.full_search_result', {
                            pattern: props.useGlob ? inputData.match : '*' + inputData.match + '*',
                        })
                    }}
                </n-tooltip>
            </template>
            <template #suffix>
                <template v-if="props.useGlob">
                    <n-tooltip placement="bottom" trigger="hover">
                        <template #trigger>
                            <n-tag
                                v-model:checked="inputData.exact"
                                :checkable="true"
                                :type="props.exact ? 'primary' : 'default'"
                                size="small"
                                strong
                                style="padding: 0 5px"
                                @updateChecked="onExactChecked">
                                <n-icon :size="14">
                                    <spell-check :stroke-width="2" />
                                </n-icon>
                            </n-tag>
                        </template>
                        <div class="text-block" style="max-width: 600px">
                            {{ $t('dialogue.filter.exact_match_tip') }}
                        </div>
                    </n-tooltip>
                </template>
            </template>
        </n-input>

        <icon-button
            v-if="props.fullSearchIcon"
            :disabled="hasMatch && !hasFilter"
            :icon="props.fullSearchIcon"
            :size="small ? 16 : 20"
            :tooltip-delay="1"
            border
            small
            stroke-width="4"
            @click="onFullSearch">
            <template #tooltip>
                <div class="text-block" style="max-width: 600px">
                    {{ $t('dialogue.filter.filter_pattern_tip') }}
                </div>
            </template>
        </icon-button>
        <n-button v-else :disabled="hasMatch && !hasFilter" :focusable="false" @click="onFullSearch">
            {{ $t('interface.full_search') }}
        </n-button>
        <slot name="append" />
    </n-input-group>
</template>

<style lang="scss" scoped>
:deep(.n-input) {
    width: 100%;
    overflow: hidden;
}

:deep(.n-input__prefix) {
    max-width: 50%;

    & > div {
        overflow: hidden;
        text-overflow: ellipsis;
    }
}

:deep(.n-tag__content) {
    overflow: hidden;
    max-width: 100%;
}
</style>
