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

import FetchData from 'components/FetchData.vue';
import FetchedTags from 'components/ui/FetchedTags.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnInputDate from 'src/components/common/VnInputDate.vue';
import EditTableCellValueForm from 'src/components/EditTableCellValueForm.vue';
import ItemFixedPriceFilter from './ItemFixedPriceFilter.vue';
import ItemDescriptorProxy from './Card/ItemDescriptorProxy.vue';

import { useStateStore } from 'stores/useStateStore';
import { dashIfEmpty } from 'src/filters';
import { useVnConfirm } from 'composables/useVnConfirm';
import { useState } from 'src/composables/useState';
import { toCurrency } from 'filters/index';
import useNotify from 'src/composables/useNotify.js';
import axios from 'axios';
import { useArrayData } from 'composables/useArrayData';
import { isLower, isBigger } from 'src/filters/date.js';
import RightMenu from 'src/components/common/RightMenu.vue';

const stateStore = useStateStore();
const { t } = useI18n();
const { openConfirmationModal } = useVnConfirm();
const state = useState();
const { notify } = useNotify();

const editTableCellDialogRef = ref(null);
const user = state.getUser();
const fixedPrices = ref([]);
const fixedPricesOriginalData = ref([]);
const warehousesOptions = ref([]);
const rowsSelected = ref([]);

const exprBuilder = (param, value) => {
    switch (param) {
        case 'name':
            return { 'i.name': { like: `%${value}%` } };
        case 'itemFk':
        case 'warehouseFk':
        case 'rate2':
        case 'rate3':
            param = `fp.${param}`;
            return { [param]: value };
        case 'minPrice':
            param = `i.${param}`;
            return { [param]: value };
    }
};

const params = reactive({});
const arrayData = useArrayData('ItemFixedPrices', {
    url: 'FixedPrices/filter',
    userParams: params,
    order: ['name ASC', 'itemFk'],
    exprBuilder: exprBuilder,
});
const store = arrayData.store;

const fetchFixedPrices = async () => {
    await arrayData.fetch({ append: false });
};

const onFixedPricesFetched = (data) => {
    fixedPrices.value = data;
    // el objetivo de guardar una copia de las rows es evitar guardar cambios si la data no cambió al disparar los eventos
    fixedPricesOriginalData.value = JSON.parse(JSON.stringify(data));
};

watch(
    () => store.data,
    (data) => onFixedPricesFetched(data)
);

const applyColumnFilter = async (col) => {
    try {
        const paramKey = col.columnFilter?.filterParamKey || col.field;
        params[paramKey] = col.columnFilter.filterValue;
        await arrayData.addFilter({ params });
    } catch (err) {
        console.error('Error applying column filter', err);
    }
};

const getColumnInputEvents = (col) => {
    return col.columnFilter.type === 'select'
        ? { 'update:modelValue': () => applyColumnFilter(col) }
        : {
              'keyup.enter': () => applyColumnFilter(col),
          };
};

const defaultColumnFilter = {
    component: VnInput,
    type: 'text',
    filterValue: null,
    event: getColumnInputEvents,
    attrs: {
        dense: true,
    },
};

const defaultColumnAttrs = {
    align: 'left',
    sortable: true,
};

const columns = computed(() => [
    {
        label: t('item.fixedPrice.itemId'),
        name: 'itemId',
        field: 'itemFk',
        ...defaultColumnAttrs,
        columnFilter: {
            ...defaultColumnFilter,
        },
    },
    {
        label: t('globals.description'),
        field: 'name',
        name: 'description',
        ...defaultColumnAttrs,
        columnFilter: {
            ...defaultColumnFilter,
        },
    },
    {
        label: t('item.fixedPrice.groupingPrice'),
        field: 'rate2',
        name: 'groupingPrice',
        ...defaultColumnAttrs,
        columnFilter: {
            ...defaultColumnFilter,
        },
        format: (val) => toCurrency(val),
    },
    {
        label: t('item.fixedPrice.packingPrice'),
        field: 'rate3',
        name: 'packingPrice',
        ...defaultColumnAttrs,
        columnFilter: {
            ...defaultColumnFilter,
        },
        format: (val) => dashIfEmpty(val),
    },

    {
        label: t('item.fixedPrice.minPrice'),
        field: 'minPrice',
        name: 'minPrice',
        ...defaultColumnAttrs,
        columnFilter: {
            ...defaultColumnFilter,
        },
    },
    {
        label: t('item.fixedPrice.started'),
        field: 'started',
        name: 'started',
        ...defaultColumnAttrs,
        columnFilter: null,
    },
    {
        label: t('item.fixedPrice.ended'),
        field: 'ended',
        name: 'ended',
        ...defaultColumnAttrs,
        columnFilter: null,
    },

    {
        label: t('item.fixedPrice.warehouse'),
        field: 'warehouseFk',
        name: 'warehouse',
        ...defaultColumnAttrs,
        columnFilter: {
            component: VnSelect,
            type: 'select',
            filterValue: null,
            event: getColumnInputEvents,
            attrs: {
                options: warehousesOptions.value,
                'option-value': 'id',
                'option-label': 'name',
                dense: true,
            },
        },
    },
    { name: 'deleteAction', align: 'center' },
]);

const editTableFieldsOptions = [
    {
        field: 'rate2',
        label: t('item.fixedPrice.groupingPrice'),
        component: 'input',
        attrs: {
            type: 'number',
        },
    },
    {
        field: 'rate3',
        label: t('item.fixedPrice.packingPrice'),
        component: 'input',
        attrs: {
            type: 'number',
        },
    },
    {
        field: 'minPrice',
        label: t('item.fixedPrice.minPrice'),
        component: 'input',
        attrs: {
            type: 'number',
        },
    },
    {
        field: 'hasMinPrice',
        label: t('item.fixedPrice.hasMinPrice'),
        component: 'checkbox',
        attrs: {
            'false-value': 0,
            'true-value': 1,
        },
    },
    {
        field: 'started',
        label: t('item.fixedPrice.started'),
        component: 'date',
    },
    {
        field: 'ended',
        label: t('item.fixedPrice.ended'),
        component: 'date',
    },
    {
        field: 'warehouseFk',
        label: t('item.fixedPrice.warehouse'),
        component: 'select',
        attrs: {
            options: [],
            'option-label': 'name',
            'option-value': 'id',
        },
    },
];

const getRowUpdateInputEvents = (props, resetMinPrice, inputType = 'text') => {
    return inputType === 'text'
        ? {
              'keyup.enter': () => upsertPrice(props, resetMinPrice),
              blur: () => upsertPrice(props, resetMinPrice),
          }
        : { 'update:modelValue': () => upsertPrice(props, resetMinPrice) };
};

const validations = (row, rowIndex, col) => {
    const isNew = !row.id;
    // Si la row no tiene id significa que fue agregada con addRow y no se ha guardado en la base de datos
    // Si isNew es falso no se checkea si el valor es igual a la original
    if (!isNew)
        if (fixedPricesOriginalData.value[rowIndex][col.field] == row[col.field])
            return false;

    const requiredFields = ['itemFk', 'started', 'ended', 'rate2', 'rate3'];
    return requiredFields.every(
        (field) => row[field] !== null && row[field] !== undefined
    );
};

const upsertPrice = async ({ row, col, rowIndex }, resetMinPrice = false) => {
    if (!validations(row, rowIndex, col)) return;

    try {
        if (resetMinPrice) row.hasMinPrice = 0;

        const { data } = await axios.patch('FixedPrices/upsertFixedPrice', row);
        row = data;
        fixedPricesOriginalData.value[rowIndex][col.field] = row[col.field];
    } catch (err) {
        console.error('Error editing price', err);
    }
};

const addRow = () => {
    if (!fixedPrices.value || fixedPrices.value.length === 0) {
        fixedPrices.value = [];

        const today = Date.vnNew();
        const millisecsInDay = 86400000;
        const daysInWeek = 7;
        const nextWeek = new Date(today.getTime() + daysInWeek * millisecsInDay);

        const newPrice = {
            started: today,
            ended: nextWeek,
            hasMinPrice: 0,
        };

        fixedPricesOriginalData.value.push({ ...newPrice });
        fixedPrices.value.push({ ...newPrice });
        return;
    }

    const lastItemCopy = JSON.parse(
        JSON.stringify(fixedPrices.value[fixedPrices.value.length - 1])
    );
    delete lastItemCopy.id;
    fixedPricesOriginalData.value.push(lastItemCopy);
    fixedPrices.value.push(lastItemCopy);
};

const openEditTableCellDialog = () => {
    editTableCellDialogRef.value.show();
};

const onEditCellDataSaved = async () => {
    rowsSelected.value = [];
    await fetchFixedPrices();
};

const onWarehousesFetched = (data) => {
    warehousesOptions.value = data;
    // Actualiza las 'options' del elemento con field 'warehouseFk' en 'editTableFieldsOptions'.
    const warehouseField = editTableFieldsOptions.find(
        (field) => field.field === 'warehouseFk'
    );
    warehouseField.attrs.options = data;
};

const removePrice = async (id, rowIndex) => {
    try {
        await axios.delete(`FixedPrices/${id}`);
        fixedPrices.value.splice(rowIndex, 1);
        fixedPricesOriginalData.value.splice(rowIndex, 1);
        notify(t('globals.dataSaved'), 'positive');
    } catch (err) {
        console.error('Error removing price', err);
    }
};

const updateMinPrice = async (value, props) => {
    // El checkbox hasMinPrice se encuentra en la misma columna que el input hasMinPrice
    // Por lo tanto le mandamos otro objeto con las mismas propiedades pero con el campo 'field' cambiado
    props.row.hasMinPrice = value;
    await upsertPrice({
        row: props.row,
        col: { field: 'hasMinPrice' },
        rowIndex: props.rowIndex,
    });
};

onMounted(async () => {
    stateStore.rightDrawer = true;
    params.warehouseFk = user.value.warehouseFk;
    await fetchFixedPrices();
});

onUnmounted(() => (stateStore.rightDrawer = false));
</script>

<template>
    <FetchData
        url="Warehouses"
        :filter="{ order: ['name'] }"
        auto-load
        @on-fetch="(data) => onWarehousesFetched(data)"
    />
    <RightMenu>
        <template #right-panel>
            <ItemFixedPriceFilter
                data-key="ItemFixedPrices"
                :warehouses-options="warehousesOptions"
            />
        </template>
    </RightMenu>
    <QPage class="column items-center q-pa-md">
        <QTable
            :rows="fixedPrices"
            :columns="columns"
            row-key="id"
            selection="multiple"
            v-model:selected="rowsSelected"
            :pagination="{ rowsPerPage: 0 }"
            class="full-width q-mt-md"
            :no-data-label="t('globals.noResults')"
        >
            <template #top-row="{ cols }">
                <QTr>
                    <QTd />
                    <QTd
                        v-for="(col, index) in cols"
                        :key="index"
                        style="max-width: 100px"
                    >
                        <component
                            :is="col.columnFilter.component"
                            v-if="col.columnFilter"
                            v-model="col.columnFilter.filterValue"
                            v-bind="col.columnFilter.attrs"
                            v-on="col.columnFilter.event(col)"
                            dense
                        />
                    </QTd>
                </QTr>
            </template>

            <template #body-cell-itemId="props">
                <QTd>
                    <VnSelect
                        url="Items/withName"
                        hide-selected
                        option-label="id"
                        option-value="id"
                        v-model="props.row.itemFk"
                        v-on="getRowUpdateInputEvents(props, true, 'select')"
                    >
                        <template #option="scope">
                            <QItem v-bind="scope.itemProps">
                                <QItemSection>
                                    <QItemLabel> #{{ scope.opt?.id }} </QItemLabel>
                                    <QItemLabel caption>{{ scope.opt?.name }}</QItemLabel>
                                </QItemSection>
                            </QItem>
                        </template>
                    </VnSelect>
                </QTd>
            </template>
            <template #body-cell-description="{ row }">
                <QTd class="col">
                    <span class="link">
                        {{ row.name }}
                    </span>
                    <ItemDescriptorProxy :id="row.itemFk" />
                    <FetchedTags :item="row" />
                </QTd>
            </template>
            <template #body-cell-groupingPrice="props">
                <QTd class="col">
                    <VnInput
                        v-model.number="props.row.rate2"
                        v-on="getRowUpdateInputEvents(props)"
                    >
                        <template #append>€</template>
                    </VnInput>
                </QTd>
            </template>
            <template #body-cell-packingPrice="props">
                <QTd class="col">
                    <VnInput
                        v-model.number="props.row.rate3"
                        v-on="getRowUpdateInputEvents(props)"
                    >
                        <template #append>€</template>
                    </VnInput>
                </QTd>
            </template>
            <template #body-cell-minPrice="props">
                <QTd class="col">
                    <div class="row">
                        <QCheckbox
                            class="col"
                            :model-value="props.row.hasMinPrice"
                            @update:model-value="updateMinPrice($event, props)"
                            :false-value="0"
                            :true-value="1"
                            :toggle-indeterminate="false"
                        />
                        <VnInput
                            class="col"
                            :disable="!props.row.hasMinPrice"
                            v-model.number="props.row.minPrice"
                            v-on="getRowUpdateInputEvents(props)"
                            type="number"
                        />
                    </div>
                </QTd>
            </template>
            <template #body-cell-started="props">
                <QTd class="col" style="min-width: 160px">
                    <VnInputDate
                        v-model="props.row.started"
                        v-on="getRowUpdateInputEvents(props, false, 'date')"
                        v-bind="
                            isBigger(props.row.started)
                                ? { 'bg-color': 'warning', 'is-outlined': true }
                                : {}
                        "
                    />
                </QTd>
            </template>
            <template #body-cell-ended="props">
                <QTd class="col" style="min-width: 150px">
                    <VnInputDate
                        v-model="props.row.ended"
                        v-on="getRowUpdateInputEvents(props, false, 'date')"
                        v-bind="
                            isLower(props.row.ended)
                                ? { 'bg-color': 'warning', 'is-outlined': true }
                                : {}
                        "
                    />
                </QTd>
            </template>
            <template #body-cell-warehouse="props">
                <QTd class="col">
                    <VnSelect
                        :options="warehousesOptions"
                        hide-selected
                        option-label="name"
                        option-value="id"
                        v-model="props.row.warehouseFk"
                        v-on="getRowUpdateInputEvents(props, false, 'select')"
                    />
                </QTd>
            </template>
            <template #body-cell-deleteAction="{ row, rowIndex }">
                <QTd class="col">
                    <QIcon
                        name="delete"
                        size="sm"
                        class="cursor-pointer fill-icon-on-hover"
                        color="primary"
                        @click.stop="
                            openConfirmationModal(
                                t('This row will be removed'),
                                t('Do you want to clone this item?'),
                                () => removePrice(row.id, rowIndex)
                            )
                        "
                    >
                        <QTooltip class="text-no-wrap">
                            {{ t('Delete') }}
                        </QTooltip>
                    </QIcon>
                </QTd>
            </template>
            <template #bottom-row>
                <QTd align="center">
                    <QIcon
                        @click.stop="addRow()"
                        class="fill-icon-on-hover"
                        color="primary"
                        name="add_circle"
                        size="sm"
                    >
                        <QTooltip>
                            {{ t('Add fixed price') }}
                        </QTooltip>
                    </QIcon>
                </QTd>
            </template>
        </QTable>
        <QPageSticky v-if="rowsSelected.length" :offset="[20, 20]">
            <QBtn @click="openEditTableCellDialog()" color="primary" fab icon="edit" />
            <QTooltip>
                {{ t('Edit fixed price(s)') }}
            </QTooltip>
        </QPageSticky>
        <QDialog ref="editTableCellDialogRef">
            <EditTableCellValueForm
                edit-url="FixedPrices/editFixedPrice"
                :rows="rowsSelected"
                :fields-options="editTableFieldsOptions"
                @on-data-saved="onEditCellDataSaved()"
            />
        </QDialog>
    </QPage>
</template>

<i18n>
es:
    Add fixed price: Añadir precio fijado
    Edit fixed price(s): Editar precio(s) fijado(s)
    This row will be removed: Esta linea se eliminará
    Are you sure you want to continue?: ¿Seguro que quieres continuar?
    Delete: Eliminar
</i18n>
