<script setup>
import { computed, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import ContentToolbar from './ContentToolbar.vue'
import Copy from '@/components/icons/Copy.vue'
import Save from '@/components/icons/Save.vue'
import { useThemeVars } from 'naive-ui'
import { decodeTypes, formatTypes } from '@/consts/value_view_type.js'
import Close from '@/components/icons/Close.vue'
import { types as redisTypes } from '@/consts/support_redis_type.js'
import { ClipboardSetText } from 'wailsjs/runtime/runtime.js'
import { isEmpty, toLower } from 'lodash'
import DropdownSelector from '@/components/content_value/DropdownSelector.vue'
import Code from '@/components/icons/Code.vue'
import Conversion from '@/components/icons/Conversion.vue'
import EditFile from '@/components/icons/EditFile.vue'
import bytes from 'bytes'
import useBrowserStore from 'stores/browser.js'

const i18n = useI18n()
const themeVars = useThemeVars()

const props = defineProps({
    name: String,
    db: Number,
    keyPath: String,
    keyCode: {
        type: Array,
        default: null,
    },
    ttl: {
        type: Number,
        default: -1,
    },
    value: String,
    size: Number,
    length: Number,
    viewAs: {
        type: String,
        default: formatTypes.PLAIN_TEXT,
    },
    decode: {
        type: String,
        default: decodeTypes.NONE,
    },
    loading: Boolean,
})

const emit = defineEmits(['reload', 'rename', 'delete'])

/**
 *
 * @type {ComputedRef<string|number[]>}
 */
const keyName = computed(() => {
    return !isEmpty(props.keyCode) ? props.keyCode : props.keyPath
})

const keyType = redisTypes.STRING
const viewLanguage = computed(() => {
    switch (props.viewAs) {
        case formatTypes.JSON:
            return 'json'
        default:
            return 'plaintext'
    }
})

const onViewTypeUpdate = (viewType) => {
    browserStore.loadKeyDetail({
        server: props.name,
        db: props.db,
        key: keyName.value,
        viewType,
        decodeType: props.decode,
    })
}

const onDecodeTypeUpdate = (decodeType) => {
    browserStore.loadKeyDetail({
        server: props.name,
        db: props.db,
        key: keyName.value,
        viewType: props.viewAs,
        decodeType,
    })
}

/**
 * Copy value
 */
const onCopyValue = () => {
    ClipboardSetText(props.value)
        .then((succ) => {
            if (succ) {
                $message.success(i18n.t('dialogue.copy_succ'))
            }
        })
        .catch((e) => {
            $message.error(e.message)
        })
}

const editValue = ref('')
const inEdit = ref(false)
const onEditValue = () => {
    editValue.value = props.value
    inEdit.value = true
}

const onCancelEdit = () => {
    inEdit.value = false
}

/**
 * Save value
 */
const browserStore = useBrowserStore()
const saving = ref(false)
const onSaveValue = async () => {
    saving.value = true
    try {
        const { success, msg } = await browserStore.setKey(
            props.name,
            props.db,
            keyName.value,
            toLower(keyType),
            editValue.value,
            -1,
            props.viewAs,
            props.decode,
        )
        if (success) {
            await browserStore.loadKeyDetail({ server: props.name, db: props.db, key: keyName.value })
            $message.success(i18n.t('dialogue.save_value_succ'))
        } else {
            $message.error(msg)
        }
    } catch (e) {
        $message.error(e.message)
    } finally {
        inEdit.value = false
        saving.value = false
    }
}
</script>

<template>
    <div class="content-wrapper flex-box-v">
        <content-toolbar
            :db="props.db"
            :key-code="keyCode"
            :key-path="keyPath"
            :key-type="keyType"
            :loading="loading"
            :server="props.name"
            :ttl="ttl"
            class="value-item-part"
            @delete="emit('delete')"
            @reload="emit('reload')"
            @rename="emit('rename')" />
        <div class="tb2 value-item-part flex-box-h">
            <div class="flex-item-expand"></div>
            <n-button-group v-if="!inEdit">
                <n-button :focusable="false" @click="onCopyValue">
                    <template #icon>
                        <n-icon :component="Copy" size="18" />
                    </template>
                    {{ $t('interface.copy_value') }}
                </n-button>
                <n-button :focusable="false" plain @click="onEditValue">
                    <template #icon>
                        <n-icon :component="EditFile" size="18" />
                    </template>
                    {{ $t('interface.edit_value') }}
                </n-button>
            </n-button-group>
            <n-button-group v-else>
                <n-button :focusable="false" :loading="saving" plain @click="onSaveValue">
                    <template #icon>
                        <n-icon :component="Save" size="18" />
                    </template>
                    {{ $t('interface.save_update') }}
                </n-button>
                <n-button :focusable="false" :loading="saving" plain @click="onCancelEdit">
                    <template #icon>
                        <n-icon :component="Close" size="18" />
                    </template>
                    {{ $t('common.cancel') }}
                </n-button>
            </n-button-group>
        </div>
        <div class="value-wrapper value-item-part flex-item-expand flex-box-v">
            <n-scrollbar v-if="!inEdit" class="flex-item-expand">
                <n-code :code="props.value" :language="viewLanguage" style="cursor: text" word-wrap />
            </n-scrollbar>
            <n-input
                v-else
                v-model:value="editValue"
                :disabled="saving"
                :resizable="false"
                class="flex-item-expand"
                type="textarea" />
        </div>
        <div class="value-footer flex-box-h">
            <n-text v-if="!isNaN(props.length)">{{ $t('interface.length') }}: {{ props.length }}</n-text>
            <n-divider v-if="!isNaN(props.length)" vertical />
            <n-text v-if="!isNaN(props.size)">{{ $t('interface.memory_usage') }}: {{ bytes(props.size) }}</n-text>
            <div class="flex-item-expand"></div>
            <dropdown-selector
                :icon="Code"
                :options="formatTypes"
                :tooltip="$t('interface.view_as')"
                :value="props.viewAs"
                @update:value="onViewTypeUpdate" />
            <n-divider vertical />
            <dropdown-selector
                :icon="Conversion"
                :options="decodeTypes"
                :tooltip="$t('interface.decode_with')"
                :value="props.decode"
                @update:value="onDecodeTypeUpdate" />
        </div>
    </div>
</template>

<style lang="scss" scoped>
.value-wrapper {
    overflow: hidden;
    border-top: v-bind('themeVars.borderColor') 1px solid;
    padding: 5px;
}

.value-footer {
    border-top: v-bind('themeVars.borderColor') 1px solid;
    background-color: v-bind('themeVars.tableHeaderColor');
}
</style>
