<script setup>
import { computed, h, nextTick, onMounted, onUnmounted, reactive, ref } from 'vue'
import Refresh from '@/components/icons/Refresh.vue'
import { debounce, isEmpty, map, size, split } from 'lodash'
import { useI18n } from 'vue-i18n'
import { NIcon, useThemeVars } from 'naive-ui'
import dayjs from 'dayjs'
import useBrowserStore from 'stores/browser.js'
import { timeout } from '@/utils/promise.js'
import AutoRefreshForm from '@/components/common/AutoRefreshForm.vue'

const themeVars = useThemeVars()

const browserStore = useBrowserStore()
const i18n = useI18n()
const props = defineProps({
    server: {
        type: String,
    },
})

const autoRefresh = reactive({
    on: false,
    interval: 5,
})

const data = reactive({
    list: [],
    sortOrder: 'descend',
    listLimit: 20,
    loading: false,
    client: '',
    keyword: '',
})

const tableRef = ref(null)

const columns = computed(() => [
    {
        title: () => i18n.t('slog.exec_time'),
        key: 'timestamp',
        sortOrder: data.sortOrder,
        sorter: 'default',
        width: 180,
        align: 'center',
        titleAlign: 'center',
        render: ({ timestamp }, index) => {
            return dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')
        },
    },
    {
        title: () => i18n.t('slog.client'),
        key: 'client',
        filterOptionValue: data.client,
        resizable: true,
        filter: (value, row) => {
            return value === '' || row.client === value.toString() || row.addr === value.toString()
        },
        width: 200,
        align: 'center',
        titleAlign: 'center',
        ellipsis: {
            tooltip: {
                style: {
                    maxWidth: '50vw',
                    maxHeight: '50vh',
                },
                scrollable: true,
            },
        },
        render: ({ client, addr }, index) => {
            let content = ''
            if (!isEmpty(client)) {
                content += client
            }
            if (!isEmpty(addr)) {
                if (!isEmpty(content)) {
                    content += ' - '
                }
                content += addr
            }
            return content
        },
    },
    {
        title: () => i18n.t('slog.cmd'),
        key: 'cmd',
        titleAlign: 'center',
        filterOptionValue: data.keyword,
        resizable: true,
        filter: (value, row) => {
            return value === '' || !!~row.cmd.indexOf(value.toString())
        },
        render: ({ cmd }, index) => {
            const cmdList = split(cmd, '\n')
            if (size(cmdList) > 1) {
                return h(
                    'div',
                    null,
                    map(cmdList, (c) => h('div', { class: 'cmd-line' }, c)),
                )
            }
            return h('div', { class: 'cmd-line' }, cmd)
        },
    },
    {
        title: () => i18n.t('slog.cost_time'),
        key: 'cost',
        width: 100,
        align: 'center',
        titleAlign: 'center',
        render: ({ cost }, index) => {
            const ms = dayjs.duration(cost).asMilliseconds()
            if (ms < 1000) {
                return `${ms} ms`
            } else {
                return `${Math.floor(ms / 1000)} s`
            }
        },
    },
])

const _loadSlowLog = () => {
    data.loading = true
    browserStore
        .getSlowLog(props.server, data.listLimit)
        .then((list) => {
            data.list = list || []
        })
        .finally(async () => {
            data.loading = false
            await nextTick()
            tableRef.value?.scrollTo({ position: data.sortOrder === 'ascend' ? 'bottom' : 'top' })
        })
}
const loadSlowLog = debounce(_loadSlowLog, 1000, { leading: true, trailing: true })

const startAutoRefresh = async () => {
    let lastExec = Date.now()
    do {
        if (!autoRefresh.on) {
            break
        }
        await timeout(100)
        if (data.loading || Date.now() - lastExec < autoRefresh.interval * 1000) {
            continue
        }
        lastExec = Date.now()
        loadSlowLog()
    } while (true)
    stopAutoRefresh()
}

const stopAutoRefresh = () => {
    autoRefresh.on = false
}

onMounted(() => loadSlowLog())

onUnmounted(() => stopAutoRefresh())

const onToggleRefresh = (on) => {
    if (on) {
        startAutoRefresh()
    } else {
        stopAutoRefresh()
    }
}

const onListLimitChanged = (limit) => {
    loadSlowLog()
}
</script>

<template>
    <div class="content-log content-container content-value fill-height flex-box-v">
        <n-form :disabled="data.loading" class="flex-item" inline>
            <n-form-item :label="$t('slog.limit')">
                <n-input-number
                    v-model:value="data.listLimit"
                    :max="9999"
                    :min="1"
                    style="width: 120px"
                    @update:value="onListLimitChanged" />
            </n-form-item>
            <n-form-item :label="$t('slog.filter')">
                <n-input v-model:value="data.keyword" clearable placeholder="" />
            </n-form-item>
            <n-form-item label="&nbsp;">
                <n-popover :delay="500" keep-alive-on-hover placement="bottom" trigger="hover">
                    <template #trigger>
                        <n-button :loading="data.loading" circle size="small" tertiary @click="_loadSlowLog">
                            <template #icon>
                                <n-icon :size="props.size">
                                    <refresh
                                        :class="{ 'auto-rotate': autoRefresh.on }"
                                        :color="autoRefresh.on ? themeVars.primaryColor : undefined"
                                        :stroke-width="autoRefresh.on ? 6 : 3" />
                                </n-icon>
                            </template>
                        </n-button>
                    </template>
                    <auto-refresh-form
                        v-model:interval="autoRefresh.interval"
                        v-model:on="autoRefresh.on"
                        :default-value="5"
                        :loading="data.loading"
                        @toggle="onToggleRefresh" />
                </n-popover>
            </n-form-item>
        </n-form>
        <n-data-table
            ref="tableRef"
            :columns="columns"
            :data="data.list"
            :loading="data.loading"
            class="flex-item-expand"
            flex-height
            striped
            @update:sorter="({ order }) => (data.sortOrder = order)" />
    </div>
</template>

<style lang="scss" scoped>
@import '@/styles/content';
</style>
