<script setup>
import axios from 'axios';
import { onMounted, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';

const { t } = useI18n();

const $props = defineProps({
    autoLoad: {
        type: Boolean,
        default: false,
    },
    url: {
        type: String,
        default: '',
    },
    data: {
        type: Array,
        default: null,
    },
    filter: {
        type: Object,
        default: null,
    },
    where: {
        type: Object,
        default: null,
    },
    sortBy: {
        type: String,
        default: '',
    },
    limit: {
        type: String,
        default: '',
    },
    rowsPerPage: {
        type: Number,
        default: 10,
    },
    offset: {
        type: Number,
        default: 500,
    },
});

const emit = defineEmits(['onFetch', 'onPaginate']);
defineExpose({ refresh });

onMounted(() => {
    if ($props.autoLoad) paginate();
});

watch(
    () => $props.data,
    () => {
        rows.value = $props.data;
    }
);

const isLoading = ref(false);
const hasMoreData = ref(false);
const pagination = ref({
    sortBy: $props.sortBy,
    rowsPerPage: $props.rowsPerPage,
    page: 1,
});
const rows = ref(null);

async function fetch() {
    const { page, rowsPerPage, sortBy } = pagination.value;

    if (!$props.url) return;

    const filter = {
        limit: rowsPerPage,
        skip: rowsPerPage * (page - 1),
    };

    Object.assign(filter, $props.filter);

    if ($props.where) filter.where = $props.where;
    if ($props.sortBy) filter.order = $props.sortBy;
    if ($props.limit) filter.limit = $props.limit;

    if (sortBy) filter.order = sortBy;

    const { data } = await axios.get($props.url, {
        params: { filter },
    });

    isLoading.value = false;

    return data;
}

async function paginate() {
    const { page, rowsPerPage, sortBy, descending } = pagination.value;

    const data = await fetch();

    if (!data) {
        isLoading.value = false;
        return;
    }

    hasMoreData.value = data.length === rowsPerPage;

    if (!rows.value) rows.value = [];
    for (const row of data) rows.value.push(row);

    pagination.value.rowsNumber = rows.value.length;
    pagination.value.page = page;
    pagination.value.rowsPerPage = rowsPerPage;
    pagination.value.sortBy = sortBy;
    pagination.value.descending = descending;

    isLoading.value = false;

    emit('onFetch', rows);
    emit('onPaginate', data);
}

async function refresh() {
    const { rowsPerPage } = pagination.value;

    const data = await fetch();

    if (!data) {
        isLoading.value = false;
        return;
    }

    hasMoreData.value = data.length === rowsPerPage;

    if (!rows.value) rows.value = [];
    rows.value = data;

    isLoading.value = false;

    emit('onFetch', rows);
}

async function onLoad(...params) {
    const done = params[1];
    if (!rows.value || rows.value.length === 0 || !$props.url) return done(false);

    pagination.value.page = pagination.value.page + 1;

    await paginate();

    const endOfPages = !hasMoreData.value;
    done(endOfPages);
}
</script>

<template>
    <q-infinite-scroll @load="onLoad" :offset="offset" class="column items-center">
        <div v-if="rows" class="card-list q-gutter-y-md">
            <slot name="body" :rows="rows"></slot>
            <div v-if="!rows.length && !isLoading" class="info-row q-pa-md text-center">
                <h5>
                    {{ t('components.smartCard.noData') }}
                </h5>
            </div>
            <div v-if="isLoading" class="info-row q-pa-md text-center">
                <q-spinner color="orange" size="md" />
            </div>
        </div>
        <div v-if="!rows" class="card-list q-gutter-y-md">
            <q-card class="card" v-for="$index in $props.rowsPerPage" :key="$index">
                <q-item v-ripple class="q-pa-none items-start cursor-pointer q-hoverable">
                    <q-item-section class="q-pa-md">
                        <q-skeleton type="rect" class="q-mb-md" square />
                        <q-skeleton type="text" square />
                        <q-skeleton type="text" class="q-mb-md" square />
                        <q-skeleton type="text" square />
                        <q-skeleton type="text" square />
                    </q-item-section>
                    <q-separator vertical />
                    <q-card-actions vertical class="justify-between">
                        <q-skeleton type="circle" class="q-mb-md" size="40px" />
                        <q-skeleton type="circle" class="q-mb-md" size="40px" />
                        <q-skeleton type="circle" class="q-mb-md" size="40px" />
                    </q-card-actions>
                </q-item>
            </q-card>
        </div>
    </q-infinite-scroll>
</template>

<style lang="scss" scoped>
.card-list {
    width: 100%;
    max-width: 60em;
}

.info-row {
    width: 100%;

    h5 {
        margin: 0;
    }
}
</style>
