<script setup>
import { onMounted, ref, computed, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { useArrayData } from 'composables/useArrayData';
import { useRoute } from 'vue-router';
import toDate from 'filters/toDate';
import VnFilterPanelChip from 'components/ui/VnFilterPanelChip.vue';

const { t } = useI18n();
const $props = defineProps({
    modelValue: {
        type: Object,
        default: () => {},
    },
    dataKey: {
        type: String,
        required: true,
    },
    searchButton: {
        type: Boolean,
        default: false,
    },
    showAll: {
        type: Boolean,
        default: true,
    },
    unremovableParams: {
        type: Array,
        required: false,
        default: () => [],
        description: `Some filters come with default search parameters and require a value.
            This prop helps us determine which filters can be removed and which cannot.`,
    },
    exprBuilder: {
        type: Function,
        default: null,
    },
    hiddenTags: {
        type: Array,
        default: () => ['filter', 'search', 'or', 'and'],
    },
    customTags: {
        type: Array,
        default: () => [],
    },
    disableSubmitEvent: {
        type: Boolean,
        default: false,
    },
    searchUrl: {
        type: String,
        default: 'params',
    },
    redirect: {
        type: Boolean,
        default: true,
    },
});

defineExpose({ search, sanitizer });
const emit = defineEmits([
    'update:modelValue',
    'refresh',
    'clear',
    'search',
    'init',
    'remove',
    'setUserParams',
]);

const arrayData = useArrayData($props.dataKey, {
    exprBuilder: $props.exprBuilder,
    searchUrl: $props.searchUrl,
    navigate: $props.redirect ? {} : null,
});
const route = useRoute();
const store = arrayData.store;
const userParams = ref({});
onMounted(() => {
    userParams.value = $props.modelValue ?? {};
    emit('init', { params: userParams.value });
});

function setUserParams(watchedParams) {
    if (!watchedParams || Object.keys(watchedParams).length == 0) return;

    if (typeof watchedParams == 'string') watchedParams = JSON.parse(watchedParams);
    if (typeof watchedParams?.filter == 'string')
        watchedParams.filter = JSON.parse(watchedParams.filter);

    watchedParams = { ...watchedParams, ...watchedParams.filter?.where };
    const order = watchedParams.filter?.order;

    delete watchedParams.filter;
    userParams.value = sanitizer(watchedParams);
    emit('setUserParams', userParams.value, order);
}

watch(
    () => route.query[$props.searchUrl],
    (val, oldValue) => (val || oldValue) && setUserParams(val)
);

watch(
    () => arrayData.store.userParams,
    (val, oldValue) => (val || oldValue) && setUserParams(val)
);

watch(
    () => $props.modelValue,
    (val) => (userParams.value = val ?? {})
);

const isLoading = ref(false);
async function search(evt) {
    try {
        if (evt && $props.disableSubmitEvent) return;

        store.filter.where = {};
        isLoading.value = true;
        const filter = { ...userParams.value, ...$props.modelValue };
        store.userParamsChanged = true;
        const { params: newParams } = await arrayData.addFilter({
            params: filter,
        });
        userParams.value = newParams;

        if (!$props.showAll && !Object.values(filter).length) store.data = [];
        emit('search');
    } finally {
        isLoading.value = false;
    }
}

async function clearFilters() {
    try {
        isLoading.value = true;
        store.userParamsChanged = true;
        arrayData.reset(['skip', 'filter.skip', 'page']);
        // Filtrar los params no removibles
        const removableFilters = Object.keys(userParams.value).filter((param) =>
            $props.unremovableParams.includes(param)
        );
        const newParams = {};
        // Conservar solo los params que no son removibles
        for (const key of removableFilters) {
            newParams[key] = userParams.value[key];
        }
        userParams.value = {};
        userParams.value = { ...newParams }; // Actualizar los params con los removibles
        await arrayData.applyFilter({ params: userParams.value });

        if (!$props.showAll) {
            store.data = [];
        }
        emit('clear');
        emit('update:modelValue', userParams.value);
    } finally {
        isLoading.value = false;
    }
}

const tagsList = computed(() => {
    const tagList = [];
    for (const key of Object.keys(userParams.value)) {
        const value = userParams.value[key];
        if (value == null || ($props.hiddenTags || []).includes(key)) continue;
        tagList.push({ label: key, value });
    }
    return tagList;
});

const tags = computed(() => {
    return tagsList.value.filter((tag) => !($props.customTags || []).includes(tag.label));
});
const customTags = computed(() =>
    tagsList.value.filter((tag) => ($props.customTags || []).includes(tag.label))
);

async function remove(key) {
    userParams.value[key] = undefined;
    search();
    emit('remove', key);
    emit('update:modelValue', userParams.value);
}

function formatValue(value) {
    if (typeof value === 'boolean') return value ? t('Yes') : t('No');
    if (isNaN(value) && !isNaN(Date.parse(value))) return toDate(value);

    return `"${value}"`;
}

function sanitizer(params) {
    for (const [key, value] of Object.entries(params)) {
        if (value && typeof value === 'object') {
            const param = Object.values(value)[0];
            if (typeof param == 'string') params[key] = param.replaceAll('%', '');
        }
    }
    return params;
}
</script>

<template>
    <QBtn
        class="q-mt-lg q-mr-xs q-mb-lg"
        round
        color="primary"
        style="position: fixed; z-index: 1; right: 0; bottom: 0"
        icon="search"
        @click="search()"
    ></QBtn>
    <QForm @submit="search" id="filterPanelForm" @keyup.enter="search()">
        <QList dense>
            <QItem class="q-mt-xs">
                <QItemSection top>
                    <QItemLabel header lines="1" class="text-uppercase q-py-xs q-px-none">
                        {{ t('Applied filters') }}
                    </QItemLabel>
                </QItemSection>
                <QItemSection top side>
                    <QBtn
                        @click="clearFilters"
                        color="primary"
                        dense
                        flat
                        icon="filter_list_off"
                        padding="none"
                        round
                        size="sm"
                    >
                        <QTooltip>{{ t('Remove filters') }}</QTooltip>
                    </QBtn>
                </QItemSection>
            </QItem>
            <QItem class="q-mb-sm">
                <div
                    v-if="tagsList.length === 0"
                    class="text-grey font-xs text-center full-width"
                >
                    {{ t(`No filters applied`) }}
                </div>
                <div>
                    <VnFilterPanelChip
                        v-for="chip of tags"
                        :key="chip.label"
                        :removable="!unremovableParams?.includes(chip.label)"
                        @remove="remove(chip.label)"
                    >
                        <slot name="tags" :tag="chip" :format-fn="formatValue">
                            <div class="q-gutter-x-xs">
                                <strong>{{ chip.label }}:</strong>
                                <span>"{{ formatValue(chip.value) }}"</span>
                            </div>
                        </slot>
                    </VnFilterPanelChip>
                    <slot
                        v-if="$slots.customTags"
                        name="customTags"
                        :params="userParams"
                        :tags="customTags"
                        :format-fn="formatValue"
                        :search-fn="search"
                    />
                </div>
            </QItem>
            <QSeparator />
        </QList>
        <QList dense class="list q-gutter-y-sm q-mt-sm">
            <slot name="body" :params="sanitizer(userParams)" :search-fn="search"></slot>
        </QList>
    </QForm>
    <QInnerLoading
        :label="t('globals.pleaseWait')"
        :showing="isLoading"
        color="primary"
    />
</template>
<style scoped lang="scss">
.list {
    width: 256px;
}
</style>

<i18n>
es:
    No filters applied: No se han aplicado filtros
    Applied filters: Filtros aplicados
    Remove filters: Eliminar filtros
    Refresh: Refrescar
    Search: Buscar
    Yes: Si
    No: No
</i18n>
