<template>
    <div style="display: flex; align-items: center; justify-content: space-between">
        <div style="display: flex; align-items: center">
            <Button
                class="rounded-full"
                variant="ghost"
                size="icon-sm"
                :disabled="userDialog.isWorldsLoading"
                @click="refreshUserDialogWorlds()">
                <Spinner v-if="userDialog.isWorldsLoading" />
                <RefreshCw v-else />
            </Button>
            <span style="margin-left: 6px">{{
                t('dialog.user.worlds.total_count', { count: userDialog.worlds.length })
            }}</span>
        </div>
        <div style="display: flex; align-items: center">
            <span class="mr-1">{{ t('dialog.user.worlds.sort_by') }}</span>
            <Select
                :model-value="userDialogWorldSortingKey"
                :disabled="userDialog.isWorldsLoading"
                @update:modelValue="setUserDialogWorldSortingByKey">
                <SelectTrigger size="sm" @click.stop>
                    <SelectValue />
                </SelectTrigger>
                <SelectContent>
                    <SelectItem
                        v-for="(item, key) in userDialogWorldSortingOptions"
                        :key="String(key)"
                        :value="String(key)">
                        {{ t(item.name) }}
                    </SelectItem>
                </SelectContent>
            </Select>
            <span class="ml-2 mr-1">{{ t('dialog.user.worlds.order_by') }}</span>
            <Select
                :model-value="userDialogWorldOrderKey"
                :disabled="userDialog.isWorldsLoading"
                @update:modelValue="setUserDialogWorldOrderByKey">
                <SelectTrigger size="sm" @click.stop>
                    <SelectValue />
                </SelectTrigger>
                <SelectContent>
                    <SelectItem
                        v-for="(item, key) in userDialogWorldOrderOptions"
                        :key="String(key)"
                        :value="String(key)">
                        {{ t(item.name) }}
                    </SelectItem>
                </SelectContent>
            </Select>
        </div>
    </div>
    <div class="flex flex-wrap items-start" style="margin-top: 8px; min-height: 60px">
        <template v-if="userDialog.worlds.length">
            <div
                v-for="world in userDialog.worlds"
                :key="world.id"
                class="box-border flex items-center p-1.5 text-[13px] cursor-pointer w-[167px] hover:rounded-[25px_5px_5px_25px]"
                @click="showWorldDialog(world.id)">
                <div class="relative inline-block flex-none size-9 mr-2.5">
                    <img class="size-full rounded-full object-cover" :src="world.thumbnailImageUrl" loading="lazy" />
                </div>
                <div class="flex-1 overflow-hidden">
                    <span class="block truncate font-medium leading-[18px]" v-text="world.name"></span>
                    <span v-if="world.occupants" class="block truncate text-xs">({{ world.occupants }})</span>
                </div>
            </div>
        </template>
        <div
            v-else-if="!userDialog.isWorldsLoading"
            style="display: flex; justify-content: center; align-items: center; min-height: 120px; width: 100%">
            <DataTableEmpty type="nodata" />
        </div>
    </div>
</template>

<script setup>
    import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
    import { Button } from '@/components/ui/button';
    import { DataTableEmpty } from '@/components/ui/data-table';
    import { RefreshCw } from 'lucide-vue-next';
    import { Spinner } from '@/components/ui/spinner';
    import { ref } from 'vue';
    import { storeToRefs } from 'pinia';
    import { useI18n } from 'vue-i18n';

    import { useUserStore, useWorldStore } from '../../../stores';
    import { userDialogWorldOrderOptions, userDialogWorldSortingOptions } from '../../../shared/constants/';
    import { useOptionKeySelect } from '../../../composables/useOptionKeySelect';
    import { worldRequest } from '../../../api';

    const { t } = useI18n();

    const userStore = useUserStore();
    const { userDialog, currentUser } = storeToRefs(userStore);
    const { cachedWorlds, showWorldDialog } = useWorldStore();

    const userDialogWorldsRequestId = ref(0);

    /**
     *
     * @param userId
     */
    function setUserDialogWorlds(userId) {
        const worlds = [];
        for (const ref of cachedWorlds.values()) {
            if (ref.authorId === userId) {
                worlds.push(ref);
            }
        }
        userDialog.value.worlds = worlds;
    }

    /**
     *
     */
    function refreshUserDialogWorlds() {
        const D = userDialog.value;
        if (D.isWorldsLoading) {
            return;
        }
        const requestId = ++userDialogWorldsRequestId.value;
        D.isWorldsLoading = true;
        const params = {
            n: 50,
            offset: 0,
            sort: userDialog.value.worldSorting.value,
            order: userDialog.value.worldOrder.value,
            // user: 'friends',
            userId: D.id,
            releaseStatus: 'public'
        };
        if (params.userId === currentUser.value.id) {
            params.user = 'me';
            params.releaseStatus = 'all';
        }
        const worlds = [];
        const worldIds = new Set();
        (async () => {
            try {
                let offset = 0;
                while (true) {
                    const args = await worldRequest.getCachedWorlds({
                        ...params,
                        offset
                    });
                    if (requestId !== userDialogWorldsRequestId.value || D.id !== params.userId) {
                        return;
                    }
                    for (const world of args.json) {
                        if (!worldIds.has(world.id)) {
                            worldIds.add(world.id);
                            worlds.push(world);
                        }
                    }
                    if (args.json.length < params.n) {
                        break;
                    }
                    offset += params.n;
                }
                if (requestId === userDialogWorldsRequestId.value && D.id === params.userId) {
                    userDialog.value.worlds = worlds;
                }
            } finally {
                if (requestId === userDialogWorldsRequestId.value) {
                    D.isWorldsLoading = false;
                }
            }
        })().catch((err) => {
            console.error('refreshUserDialogWorlds failed', err);
        });
    }

    /**
     *
     * @param sortOrder
     */
    async function setUserDialogWorldSorting(sortOrder) {
        const D = userDialog.value;
        if (D.worldSorting.value === sortOrder.value) {
            return;
        }
        D.worldSorting = sortOrder;
        refreshUserDialogWorlds();
    }

    const { selectedKey: userDialogWorldSortingKey, selectByKey: setUserDialogWorldSortingByKey } = useOptionKeySelect(
        userDialogWorldSortingOptions,
        () => userDialog.value.worldSorting,
        setUserDialogWorldSorting
    );

    /**
     *
     * @param order
     */
    async function setUserDialogWorldOrder(order) {
        const D = userDialog.value;
        if (D.worldOrder.value === order.value) {
            return;
        }
        D.worldOrder = order;
        refreshUserDialogWorlds();
    }

    const { selectedKey: userDialogWorldOrderKey, selectByKey: setUserDialogWorldOrderByKey } = useOptionKeySelect(
        userDialogWorldOrderOptions,
        () => userDialog.value.worldOrder,
        setUserDialogWorldOrder
    );

    defineExpose({ setUserDialogWorlds, refreshUserDialogWorlds });
</script>
