<script setup>
import axios from 'axios';
import { onMounted, watch, ref, reactive, computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { QSeparator, useQuasar } from 'quasar';
import { useRoute } from 'vue-router';
import { useNavigationStore } from 'src/stores/useNavigationStore';
import { toLowerCamel } from 'src/filters';
import routes from 'src/router/modules';
import LeftMenuItem from './LeftMenuItem.vue';
import LeftMenuItemGroup from './LeftMenuItemGroup.vue';
import VnInput from './common/VnInput.vue';
import { useRouter } from 'vue-router';

const { t } = useI18n();
const route = useRoute();
const quasar = useQuasar();
const navigation = useNavigationStore();
const router = useRouter();
const props = defineProps({
    source: {
        type: String,
        default: 'main',
    },
});
const initialized = ref(false);
const items = ref([]);
const expansionItemElements = reactive({});
const pinnedModules = computed(() => {
    const map = new Map();
    items.value.forEach((item) => item.isPinned && map.set(item.name, item));
    return map;
});
const search = ref(null);

const filteredItems = computed(() => {
    if (!search.value) return items.value;
    const normalizedSearch = normalize(search.value);
    return items.value.filter((item) => {
        const locale = normalize(t(item.title));
        return locale.includes(normalizedSearch);
    });
});
const filteredPinnedModules = computed(() => {
    if (!search.value) return pinnedModules.value;
    const normalizedSearch = search.value
        .normalize('NFD')
        .replace(/[\u0300-\u036f]/g, '')
        .toLowerCase();
    const map = new Map();
    for (const [key, pinnedModule] of pinnedModules.value) {
        const locale = t(pinnedModule.title)
            .normalize('NFD')
            .replace(/[\u0300-\u036f]/g, '')
            .toLowerCase();
        if (locale.includes(normalizedSearch)) map.set(key, pinnedModule);
    }
    return map;
});

onMounted(async () => {
    await navigation.fetchPinned();
    getRoutes();
    initialized.value = true;
});

watch(
    () => route.matched,
    () => {
        if (!initialized.value) return;
        items.value = [];
        getRoutes();
    },
    { deep: true },
);

function findMatches(search, item) {
    const matches = [];
    function findRoute(search, item) {
        if (!item?.children) return;
        for (const child of item.children) {
            if (search?.indexOf(child.name) > -1) {
                matches.push(child);
            } else if (child.children) {
                findRoute(search, child);
            }
        }
    }

    findRoute(search, item);

    return matches;
}

function addChildren(module, route, parent) {
    const menus = route?.meta?.menu;
    if (!menus) return;

    const matches = findMatches(menus, route);

    for (const child of matches) {
        navigation.addMenuItem(module, child, parent);
    }
}

function getRoutes() {
    const handleRoutes = {
        main: getMainRoutes,
        card: getCardRoutes,
    };
    handleRoutes[props.source]();
}
function getMainRoutes() {
    const modules = Object.assign([], navigation.getModules().value);

    for (const item of modules) {
        const moduleDef = routes.find(
            (route) => toLowerCamel(route.name) === item.module,
        );
        if (!moduleDef) continue;
        item.children = [];
        addChildren(item.module, moduleDef, item.children);
    }

    items.value = modules;
}

function getCardRoutes() {
    const currentRoute = route.matched[1];
    const currentModule = toLowerCamel(currentRoute.name);
    let moduleDef;

    let index = route.matched.length - 1;
    while (!moduleDef && index > 0) {
        if (route.matched[index]?.meta?.menu) moduleDef = route.matched[index];
        index--;
    }

    if (!moduleDef) return;
    addChildren(currentModule, moduleDef, items.value);
}

async function togglePinned(item, event) {
    if (event.defaultPrevented) return;
    event.preventDefault();
    event.stopPropagation();

    const data = { moduleName: item.module };
    const response = await axios.post('StarredModules/toggleStarredModule', data);

    item.isPinned = false;

    if (response.data && response.data.id) {
        item.isPinned = true;
    }

    navigation.togglePinned(item.module);

    quasar.notify({
        message: t('globals.dataSaved'),
        type: 'positive',
    });
}

const handleItemExpansion = (itemName) => {
    expansionItemElements[itemName].scrollToLastElement();
};

function normalize(text) {
    return text
        .normalize('NFD')
        .replace(/[\u0300-\u036f]/g, '')
        .toLowerCase();
}
const searchModule = () => {
    const [item] = filteredItems.value;
    if (item) router.push({ name: item.name });
};
</script>

<template>
    <QList padding class="column-max-width">
        <template v-if="$props.source === 'main'">
            <template v-if="route?.matched[1]?.name === 'Dashboard'">
                <QItem class="q-pb-md">
                    <VnInput
                        v-model="search"
                        :label="t('Search modules')"
                        class="full-width"
                        filled
                        dense
                        autofocus
                        @keyup.enter.stop="searchModule()"
                    />
                </QItem>
                <QSeparator />
                <template v-if="filteredPinnedModules.size && !search">
                    <LeftMenuItem
                        v-for="[key, pinnedModule] of filteredPinnedModules"
                        :key="key"
                        :item="pinnedModule"
                        group="modules"
                    >
                        <template #side>
                            <QBtn
                                v-if="pinnedModule.isPinned === true"
                                @click="togglePinned(pinnedModule, $event)"
                                icon="remove_circle"
                                size="xs"
                                flat
                                round
                            >
                                <QTooltip>
                                    {{ t('components.leftMenu.removeFromPinned') }}
                                </QTooltip>
                            </QBtn>
                        </template>
                    </LeftMenuItem>
                    <QSeparator />
                </template>
                <template v-for="(item, index) in filteredItems" :key="item.name">
                    <template
                        v-if="
                            search ||
                            (item.children && !filteredPinnedModules.has(item.name))
                        "
                    >
                        <LeftMenuItem
                            :item="item"
                            group="modules"
                            :class="search && index === 0 ? 'searched' : ''"
                        >
                            <template #side>
                                <QBtn
                                    v-if="item.isPinned === true"
                                    @click="togglePinned(item, $event)"
                                    icon="remove_circle"
                                    size="xs"
                                    flat
                                    round
                                >
                                    <QTooltip>
                                        {{ t('components.leftMenu.removeFromPinned') }}
                                    </QTooltip>
                                </QBtn>
                                <QBtn
                                    v-if="item.isPinned === false"
                                    @click="togglePinned(item, $event)"
                                    icon="push_pin"
                                    size="xs"
                                    flat
                                    round
                                >
                                    <QTooltip>
                                        {{ t('components.leftMenu.addToPinned') }}
                                    </QTooltip>
                                </QBtn>
                            </template>
                        </LeftMenuItem>
                    </template>
                </template>
            </template>

            <template v-for="item in items" :key="item.name">
                <template v-if="item.name === route?.matched[1]?.name">
                    <QItem class="header">
                        <QItemSection avatar v-if="item.icon">
                            <QIcon :name="item.icon" />
                        </QItemSection>
                        <QItemSection avatar v-if="!item.icon">
                            <QIcon name="disabled_by_default" />
                        </QItemSection>
                        <QItemSection>{{ t(item.title) }}</QItemSection>
                        <QItemSection side>
                            <slot name="side" :item="item" />
                        </QItemSection>
                    </QItem>
                    <QSeparator />
                    <template v-if="item.children">
                        <LeftMenuItemGroup :item="item" group="modules">
                            <template #side>
                                <QBtn
                                    v-if="item.isPinned === true"
                                    @click="togglePinned(item, $event)"
                                    icon="remove_circle"
                                    size="xs"
                                    flat
                                    round
                                >
                                    <QTooltip>
                                        {{ t('components.leftMenu.removeFromPinned') }}
                                    </QTooltip>
                                </QBtn>
                                <QBtn
                                    v-if="item.isPinned === false"
                                    @click="togglePinned(item, $event)"
                                    icon="push_pin"
                                    size="xs"
                                    flat
                                    round
                                >
                                    <QTooltip>
                                        {{ t('components.leftMenu.addToPinned') }}
                                    </QTooltip>
                                </QBtn>
                            </template>
                        </LeftMenuItemGroup>
                    </template>
                </template>
            </template>
        </template>
        <template v-if="$props.source === 'card'">
            <template v-for="item in items" :key="item.name">
                <LeftMenuItem v-if="!item.children" :item="item" />
                <QList v-else>
                    <QExpansionItem
                        v-ripple
                        clickable
                        :icon="item.icon"
                        :label="t(item.title)"
                        :content-inset-level="0.5"
                        @after-show="handleItemExpansion(item.name)"
                    >
                        <LeftMenuItemGroup
                            :ref="(el) => (expansionItemElements[item.name] = el)"
                            :item="item"
                        />
                    </QExpansionItem>
                </QList>
            </template>
        </template>
    </QList>
</template>

<style scoped>
.pinned .q-btn {
    visibility: hidden;
}

.pinned:hover .q-btn {
    visibility: visible;
}
.column-max-width {
    max-width: 256px;
}
.header {
    color: var(--vn-label-color);
}
.searched {
    background-color: var(--vn-section-hover-color);
}
</style>
<i18n>
    es:
        Search modules: Buscar módulos
</i18n>
