<script setup>
import { get, isEmpty, map } from 'lodash'
import { computed, nextTick, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { TestConnection } from '../../../wailsjs/go/services/connectionService.js'
import useDialog from '../../stores/dialog'
import { useMessage } from 'naive-ui'
import Close from '../icons/Close.vue'
import useConnectionStore from '../../stores/connections.js'

/**
 * Dialog for create or edit connection
 */

const dialogStore = useDialog()
const connectionStore = useConnectionStore()
const message = useMessage()
const i18n = useI18n()

const editName = ref('')
const generalForm = ref(null)
const generalFormRules = () => {
    const requiredMsg = i18n.t('field_required')
    return {
        name: { required: true, message: requiredMsg, trigger: 'input' },
        addr: { required: true, message: requiredMsg, trigger: 'input' },
        defaultFilter: { required: true, message: requiredMsg, trigger: 'input' },
        keySeparator: { required: true, message: requiredMsg, trigger: 'input' },
    }
}
const isEditMode = computed(() => !isEmpty(editName.value))

const groupOptions = computed(() => {
    const options = map(connectionStore.groups, (group) => ({
        label: group,
        value: group,
    }))
    options.splice(0, 0, {
        label: i18n.t('no_group'),
        value: '',
    })
    return options
})

const tab = ref('general')
const testing = ref(false)
const showTestResult = ref(false)
const testResult = ref('')
const showTestConnSuccResult = computed(() => {
    return isEmpty(testResult.value) && showTestResult.value === true
})
const showTestConnFailResult = computed(() => {
    return !isEmpty(testResult.value) && showTestResult.value === true
})
const formLabelWidth = computed(() => {
    // Compatible with long english word
    if (tab.value === 'advanced' && i18n.locale.value === 'en') {
        return '140px'
    }
    return '80px'
})
const predefineColors = ref(['', '#FE5959', '#FEC230', '#FEF27F', '#6CEFAF', '#46C3FC', '#B388FC', '#B0BEC5'])
const generalFormRef = ref(null)
const advanceFormRef = ref(null)

const onSaveConnection = async () => {
    // Validate general form
    await generalFormRef.value?.validate((err) => {
        if (err) {
            nextTick(() => (tab.value = 'general'))
        }
    })

    // Validate advance form
    await advanceFormRef.value?.validate((err) => {
        if (err) {
            nextTick(() => (tab.value = 'advanced'))
        }
    })

    // Store new connection
    const { success, msg } = await connectionStore.saveConnection(editName.value, generalForm.value)
    if (!success) {
        message.error(msg)
        return
    }

    message.success(i18n.t('handle_succ'))
    onClose()
}

const resetForm = () => {
    generalForm.value = connectionStore.newDefaultConnection()
    generalFormRef.value?.restoreValidation()
    showTestResult.value = false
    testResult.value = ''
    tab.value = 'general'
}

watch(
    () => dialogStore.connDialogVisible,
    (visible) => {
        if (visible) {
            editName.value = get(dialogStore.connParam, 'name', '')
            generalForm.value = dialogStore.connParam || connectionStore.newDefaultConnection()
        }
    }
)

const onTestConnection = async () => {
    testResult.value = ''
    testing.value = true
    let result = ''
    try {
        const { addr, port, username, password } = generalForm.value
        const { success = false, msg } = await TestConnection(addr, port, username, password)
        if (!success) {
            result = msg
        }
    } catch (e) {
        result = e.message
    } finally {
        testing.value = false
        showTestResult.value = true
    }

    if (!isEmpty(result)) {
        testResult.value = result
    } else {
        testResult.value = ''
    }
}

const onClose = () => {
    if (isEditMode.value) {
        dialogStore.closeEditDialog()
    } else {
        dialogStore.closeNewDialog()
    }
}
</script>

<template>
    <n-modal
        v-model:show="dialogStore.connDialogVisible"
        :closable="false"
        :close-on-esc="false"
        :mask-closable="false"
        :on-after-leave="resetForm"
        :show-icon="false"
        :title="isEditMode ? $t('edit_conn_title') : $t('new_conn_title')"
        preset="dialog"
        transform-origin="center"
    >
        <n-tabs v-model:value="tab" type="line" animated>
            <n-tab-pane :tab="$t('general')" display-directive="show" name="general">
                <n-form
                    ref="generalFormRef"
                    :label-width="formLabelWidth"
                    :model="generalForm"
                    :rules="generalFormRules()"
                    :show-require-mark="false"
                    label-align="right"
                    label-placement="left"
                >
                    <n-form-item :label="$t('conn_name')" path="name" required>
                        <n-input v-model:value="generalForm.name" :placeholder="$t('conn_name_tip')" />
                    </n-form-item>
                    <n-form-item v-if="!isEditMode" :label="$t('conn_group')" required>
                        <n-select v-model:value="generalForm.group" :options="groupOptions" />
                    </n-form-item>
                    <n-form-item :label="$t('conn_addr')" path="addr" required>
                        <n-input v-model:value="generalForm.addr" :placeholder="$t('conn_addr_tip')" />
                        <n-text style="width: 40px; text-align: center">:</n-text>
                        <n-input-number v-model:value="generalForm.port" :max="65535" :min="1" style="width: 200px" />
                    </n-form-item>
                    <n-form-item :label="$t('conn_pwd')" path="password">
                        <n-input
                            v-model:value="generalForm.password"
                            :placeholder="$t('conn_pwd_tip')"
                            show-password-on="click"
                            type="password"
                        />
                    </n-form-item>
                    <n-form-item :label="$t('conn_usr')" path="username">
                        <n-input v-model="generalForm.username" :placeholder="$t('conn_usr_tip')" />
                    </n-form-item>
                </n-form>
            </n-tab-pane>

            <n-tab-pane :tab="$t('advanced')" display-directive="show" name="advanced">
                <n-form
                    ref="advanceFormRef"
                    :label-width="formLabelWidth"
                    :model="generalForm"
                    :rules="generalFormRules()"
                    :show-require-mark="false"
                    label-align="right"
                    label-placement="left"
                >
                    <n-form-item :label="$t('conn_advn_filter')" path="defaultFilter">
                        <n-input v-model:value="generalForm.defaultFilter" :placeholder="$t('conn_advn_filter_tip')" />
                    </n-form-item>
                    <n-form-item :label="$t('conn_advn_separator')" path="keySeparator">
                        <n-input
                            v-model:value="generalForm.keySeparator"
                            :placeholder="$t('conn_advn_separator_tip')"
                        />
                    </n-form-item>
                    <n-form-item :label="$t('conn_advn_conn_timeout')" path="connTimeout">
                        <n-input-number v-model:value="generalForm.connTimeout" :max="999999" :min="1">
                            <template #suffix>
                                {{ $t('second') }}
                            </template>
                        </n-input-number>
                    </n-form-item>
                    <n-form-item :label="$t('conn_advn_exec_timeout')" path="execTimeout">
                        <n-input-number v-model:value="generalForm.execTimeout" :max="999999" :min="1">
                            <template #suffix>
                                {{ $t('second') }}
                            </template>
                        </n-input-number>
                    </n-form-item>
                    <n-form-item :label="$t('conn_advn_mark_color')" path="markColor">
                        <div
                            v-for="color in predefineColors"
                            :key="color"
                            :class="{
                                'color-preset-item_selected': generalForm.markColor === color,
                            }"
                            :style="{ backgroundColor: color }"
                            class="color-preset-item"
                            @click="generalForm.markColor = color"
                        >
                            <n-icon v-if="color === ''" :component="Close" size="24" />
                        </div>
                    </n-form-item>
                </n-form>
            </n-tab-pane>
        </n-tabs>

        <!-- test result alert-->
        <n-alert v-if="showTestConnSuccResult" title="" type="success">
            {{ $t('conn_test_succ') }}
        </n-alert>
        <n-alert v-if="showTestConnFailResult" title="" type="error">
            {{ $t('conn_test_fail') }}: {{ testResult }}
        </n-alert>

        <template #action>
            <div class="flex-item-expand">
                <n-button :loading="testing" @click="onTestConnection">{{ $t('conn_test') }}</n-button>
            </div>
            <div class="flex-item n-dialog__action">
                <n-button @click="onClose">{{ $t('cancel') }}</n-button>
                <n-button type="primary" @click="onSaveConnection">
                    {{ isEditMode ? $t('update') : $t('confirm') }}
                </n-button>
            </div>
        </template>
    </n-modal>
</template>

<style lang="scss" scoped>
.color-preset-item {
    width: 24px;
    height: 24px;
    margin-right: 2px;
    border: white 3px solid;
    cursor: pointer;

    &_selected,
    &:hover {
        border-color: #cdd0d6;
    }
}
</style>