<template>
    <suspense>
        <component :is="Default || 'div'">
            <div class="flex gap-10">
                <CategoryMenu />
                <div class="w-full flex flex-col items-center gap-4">
                    <UTable :data="productsList" :columns="columns" class="flex-1 w-full" />
                    <UPagination v-model:page="page" :total="total" :items-per-page="perPage" />
                </div>
            </div>
        </component>
    </suspense>
</template>

<script setup lang="ts">
import { ref, watch, h, resolveComponent, computed } from 'vue'
import { useFetchJson } from '@/composable/useFetchJson'
import Default from '@/layouts/default.vue'
import { useRoute, useRouter } from 'vue-router'
import type { TableColumn } from '@nuxt/ui'
import CategoryMenu from '../inner/categoryMenu.vue'
import type { Product } from '@/types/product'

const router = useRouter()
const route = useRoute()

const perPage = ref(15)
const page = computed({
    get: () => Number(route.query.p) || 1,
    set: (val: number) => {
        router.push({
            query: {
                ...route.query,
                p: val
            }
        })
    }
})
const sortField = computed({
    get: () => [
        route.query.sort as string | undefined,
        route.query.direction as 'asc' | 'desc' | undefined
    ],

    set: ([sort]: [string, 'asc' | 'desc']) => {
        const currentSort = route.query.sort as string | undefined
        const currentDirection = route.query.direction as 'asc' | 'desc' | undefined

        let query = { ...route.query }

        if (currentSort === sort) {
            if (currentDirection === 'asc') {
                query.direction = 'desc'
            } else if (currentDirection === 'desc') {
                delete query.sort
                delete query.direction
            } else {
                query.direction = 'asc'
                query.sort = sort
            }
        } else {
            query.sort = sort
            query.direction = 'asc'
        }

        router.push({ query })
    }
})

const total = ref(0)

interface ApiResponse {
    message: string
    items: Product[]
    count: number
}

const productsList = ref<Product[]>([])
const loading = ref(true)
const error = ref<string | null>(null)
const filters = computed<Record<string, string>>({
    get: () => {
        const q = { ...route.query }
        delete q.page
        delete q.sort
        delete q.direction
        return q as Record<string, string>
    },
    set: (val) => {
        const baseQuery = { ...route.query }

        Object.keys(baseQuery).forEach(key => {
            if (!['page', 'sort', 'direction'].includes(key)) {
                delete baseQuery[key]
            }
        })

        router.push({
            query: {
                ...baseQuery,
                ...val,
                page: 1
            }
        })
    }
})

function debounce(fn: Function, delay = 400) {
    let t: any
    return (...args: any[]) => {
        clearTimeout(t)
        t = setTimeout(() => fn(...args), delay)
    }
}

const updateFilter = debounce((columnId: string, val: string) => {
    const newFilters = { ...filters.value }

    if (val) newFilters[columnId] = val
    else delete newFilters[columnId]

    filters.value = newFilters
}, 400)

async function fetchProductList() {
    loading.value = true
    error.value = null

    const params = new URLSearchParams()
    Object.entries(route.query).forEach(([key, value]) => {
        if (value === undefined || value === null) return

        if (Array.isArray(value)) {
            value.forEach(v => params.append(key, String(v)))
        } else {
            params.append(key, String(value))
        }

    })

    if (route.params.category_id)
        params.append('category_id', String(route.params.category_id))

    const url = `/api/v1/restricted/list/list-products?elems=${perPage.value}&${params.toString()}`
    try {
        const response = await useFetchJson<ApiResponse>(url)
        productsList.value = response.items || []
        total.value = Number(response.count) || 0
    } catch (e: unknown) {
        error.value = e instanceof Error ? e.message : 'Failed to load products'
    } finally {
        loading.value = false
    }
}

function goToProduct(productId: number) {
    router.push({
        name: 'customer-product-details',
        params: { product_id: productId }
    })
}

function getIcon(name: string) {
    if (sortField.value[0] === name) {
        if (sortField.value[1] === 'asc') return 'i-lucide-arrow-up-narrow-wide'
        if (sortField.value[1] === 'desc') return 'i-lucide-arrow-down-wide-narrow'
    }
    return 'i-lucide-arrow-up-down'
}

const UInputNumber = resolveComponent('UInputNumber')
const UInput = resolveComponent('UInput')
const UButton = resolveComponent('UButton')
const UIcon = resolveComponent('UIcon')

const columns: TableColumn<Product>[] = [
    {
        accessorKey: 'product_id',
        header: ({ column }) => {
            return h('div', { class: 'flex flex-col gap-1' }, [
                h('div', {
                    class: 'flex items-center gap-2 cursor-pointer',
                    onClick: () => {
                        sortField.value = ['product_id', 'asc']
                    }
                }, [
                    h('span', 'ID'),
                    h(UIcon, {
                        name: getIcon('product_id')
                    })
                ]),

                h(UInput, {
                    placeholder: 'Search...',
                    modelValue: filters.value[column.id] ?? '',
                    'onUpdate:modelValue': (val: string) => {
                        updateFilter(column.id, val)
                    },
                    size: 'xs'
                })
            ])
        },
        // header: '#',
        cell: ({ row }) => `#${row.getValue('product_id') as number}`
    },
    {
        accessorKey: 'image_link',
        header: 'Image',
        cell: ({ row }) => {
            return h('img', {
                src: row.getValue('image_link') as string,
                style: 'width:40px;height:40px;object-fit:cover;'
            })
        }
    },
    {
        accessorKey: 'name',
        header: ({ column }) => {
            return h('div', { class: 'flex flex-col gap-1' }, [
                h('div', {
                    class: 'flex items-center gap-2 cursor-pointer',
                    onClick: () => {
                        sortField.value = ['name', 'asc']
                    }
                }, [
                    h('span', 'Name'),
                    h(UIcon, {
                        name: getIcon('name')
                    })
                ]),

                h(UInput, {
                    placeholder: 'Search...',
                    modelValue: filters.value[column.id] ?? '',
                    'onUpdate:modelValue': (val: string) => {
                        updateFilter(column.id, val)
                    },
                    size: 'xs'
                })
            ])
        },
        cell: ({ row }) => row.getValue('name') as string,
        filterFn: (row, columnId, value) => {
            const name = row.getValue(columnId) as string
            return name.toLowerCase().includes(value.toLowerCase())
        }
    },
    {
        accessorKey: 'quantity',
        header: ({ column }) => {
            return h('div', { class: 'flex flex-col gap-1' }, [
                h('div', {
                    class: 'flex items-center gap-2 cursor-pointer',
                    onClick: () => {
                        sortField.value = ['quantity', 'asc']
                    }
                }, [
                    h('span', 'In stock'),
                    h(UIcon, {
                        name: getIcon('quantity')
                    })
                ]),
            ])
        },
        cell: ({ row }) => row.getValue('quantity') as number
    },
    {
        accessorKey: 'count',
        header: '',
        cell: ({ row }) => {
            return h(UButton, {
                onClick: () => {
                    goToProduct(row.original.product_id)
                },
                color: 'primary',
                variant: 'solid'
            }, () => 'Show product')
        },
    }
]

watch(
    () => route.query,
    () => {
        fetchProductList()
    },
    { immediate: true }
)
</script>
