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

import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue';
import TravelDescriptorProxy from 'src/pages/Travel/Card/TravelDescriptorProxy.vue';
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
import ExtraCommunityFilter from './ExtraCommunityFilter.vue';
import VnInput from 'src/components/common/VnInput.vue';
import EntryDescriptorProxy from '../Entry/Card/EntryDescriptorProxy.vue';

import { useStateStore } from 'stores/useStateStore';
import { toCurrency } from 'src/filters';
import { useArrayData } from 'composables/useArrayData';
import { toDate } from 'src/filters';
import { usePrintService } from 'composables/usePrintService';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
import axios from 'axios';
import RightMenu from 'src/components/common/RightMenu.vue';
import VnPopup from 'src/components/common/VnPopup.vue';

const stateStore = useStateStore();
const { t } = useI18n();
const { openReport } = usePrintService();

const shippedFrom = ref(Date.vnNew());
const landedTo = ref(Date.vnNew());

const arrayData = useArrayData('ExtraCommunity', {
    url: 'Travels/extraCommunityFilter',
    limit: 0,
    order: [
        'landed ASC',
        'shipped ASC',
        'travelFk',
        'loadPriority',
        'agencyModeFk',
        'supplierName',
        'evaNotes',
    ],
    userParams: {
        continent: 'AM',
        shippedFrom: shippedFrom.value,
        landedTo: landedTo.value,
    },
});

const rows = ref([]);
const originalRowDataCopy = ref([]);
const draggedRowIndex = ref(null);
const targetRowIndex = ref(null);
const entryRowIndex = ref(null);
const draggedEntry = ref(null);
const travelKgPercentages = ref([]);

const tableColumnComponents = {
    id: {
        component: QBtn,
        attrs: { flat: true, color: 'primary' },
    },
    cargoSupplierNickname: {
        component: QBtn,
        attrs: {
            flat: true,
            color: 'primary',
            dense: true,
            class: 'supplier-name-button',
        },
    },
    agencyModeName: {
        component: 'span',
        attrs: {},
    },
    invoiceAmount: {
        component: 'span',
        attrs: {},
    },
    ref: {
        component: VnInput,
        attrs: { dense: true },
        event: (val, field, rowIndex) => ({
            'keyup.enter': () => saveFieldValue(val, field, rowIndex),
            blur: () => saveFieldValue(val, field, rowIndex),
        }),
    },
    stickers: {
        component: 'span',
        attrs: {},
    },
    percentage: {
        component: 'span',
        attrs: {},
    },
    kg: {
        component: VnInput,
        attrs: { dense: true, type: 'number', min: 0, class: 'input-number' },
        event: (val, field, rowIndex) => ({
            'keyup.enter': () => saveFieldValue(val, field, rowIndex),
            blur: () => saveFieldValue(val, field, rowIndex),
        }),
    },
    loadedKg: {
        component: 'span',
        attrs: {},
    },
    volumeKg: {
        component: 'span',
        attrs: {},
    },
    warehouseOutName: {
        component: 'span',
        attrs: {},
    },
    shipped: {
        component: 'span',
        attrs: {},
    },
    warehouseInName: {
        component: 'span',
        attrs: {},
    },
    landed: {
        component: 'span',
        attrs: {},
    },
    notes: {
        component: 'span',
        attrs: {},
    },
};

const columns = computed(() => [
    {
        label: 'id',
        field: 'id',
        name: 'id',
        align: 'center',
        showValue: true,
        sortable: true,
    },
    {
        label: t('globals.pageTitles.supplier'),
        field: 'cargoSupplierNickname',
        name: 'cargoSupplierNickname',
        align: 'left',
        showValue: true,
        sortable: true,
    },
    {
        label: t('globals.agency'),
        field: 'agencyModeName',
        name: 'agencyModeName',
        align: 'left',
        showValue: true,
        sortable: true,
    },
    {
        label: t('globals.amount'),
        name: 'invoiceAmount',
        field: 'entries',
        align: 'left',
        showValue: true,
        sortable: true,
        format: (value) =>
            toCurrency(
                value
                    ? value.reduce((sum, entry) => {
                          return sum + (entry.invoiceAmount || 0);
                      }, 0)
                    : 0
            ),
    },
    {
        label: t('globals.reference'),
        field: 'ref',
        name: 'ref',
        align: 'left',
        showValue: false,
        sortable: true,
    },
    {
        label: t('globals.packages'),
        field: 'stickers',
        name: 'stickers',
        align: 'left',
        showValue: true,
        sortable: true,
    },
    {
        label: '%',
        field: '',
        name: 'percentage',
        align: 'center',
        showValue: false,
        sortable: true,
    },
    {
        label: t('kg'),
        field: 'kg',
        name: 'kg',
        align: 'left',
        showValue: false,
        sortable: true,
    },
    {
        label: t('physicKg'),
        field: 'loadedKg',
        name: 'loadedKg',
        align: 'left',
        showValue: true,
        sortable: true,
    },
    {
        label: 'KG Vol.',
        field: 'volumeKg',
        name: 'volumeKg',
        align: 'left',
        showValue: true,
        sortable: true,
    },
    {
        label: t('globals.wareHouseOut'),
        field: 'warehouseOutName',
        name: 'warehouseOutName',
        align: 'left',
        showValue: true,
        sortable: true,
    },
    {
        label: t('shipped'),
        field: 'shipped',
        name: 'shipped',
        align: 'left',
        showValue: true,
        sortable: true,
        format: (value) => toDate(value),
    },
    {
        label: t('globals.wareHouseIn'),
        field: 'warehouseInName',
        name: 'warehouseInName',
        align: 'left',
        showValue: true,
        sortable: true,
    },
    {
        label: t('landed'),
        field: 'landed',
        name: 'landed',
        align: 'left',
        showValue: true,
        sortable: true,
        format: (value) => toDate(value),
    },
    {
        label: t('notes'),
        field: '',
        name: 'notes',
        align: 'center',
        showValue: false,
        sortable: true,
    },
]);

async function getData() {
    await arrayData.fetch({ append: false });
}

const onStoreDataChange = () => {
    const newData = JSON.parse(JSON.stringify(arrayData.store.data)) || [];
    rows.value = newData;
    // el objetivo de esto es guardar una copia de los valores iniciales de todas las rows para corroborar si la data cambio antes de guardar los cambios
    originalRowDataCopy.value = JSON.parse(JSON.stringify(newData));
};

watch(
    arrayData.store,
    () => {
        if (!arrayData.store.data) return;
        onStoreDataChange();
    },
    { deep: true, immediate: true }
);

const openReportPdf = () => {
    const params = {
        ...arrayData.store.userParams,
        limit: arrayData.store.limit,
    };

    openReport('Travels/extra-community-pdf', params);
};

const saveFieldValue = async (val, field, index) => {
    try {
        // Evitar la solicitud de guardado si el valor no ha cambiado
        if (originalRowDataCopy.value[index][field] == val) return;

        const id = rows.value[index].id;
        const params = { [field]: val };
        await axios.patch(`Travels/${id}`, params);
        // Actualizar la copia de los datos originales con el nuevo valor
        originalRowDataCopy.value[index][field] = val;

        await arrayData.fetch({ append: false });
    } catch (err) {
        console.error('Error updating travel');
    }
};

const stopEventPropagation = (event, col) => {
    // Detener la propagación del evento de los siguientes elementos para evitar el click sobre la row que dispararía  la función navigateToTravelId
    if (!['ref', 'id', 'cargoSupplierNickname', 'kg'].includes(col.name)) return;
    event.preventDefault();
    event.stopPropagation();
};

onMounted(async () => {
    stateStore.rightDrawer = true;

    shippedFrom.value.setDate(shippedFrom.value.getDate() - 2);
    shippedFrom.value.setHours(0, 0, 0, 0);

    landedTo.value.setDate(landedTo.value.getDate() + 7);
    landedTo.value.setHours(23, 59, 59, 59);
    const { data } = await axios.get('TravelKgPercentages', {
        params: { filter: JSON.stringify({ order: 'value DESC' }) },
    });

    travelKgPercentages.value = data;
    await getData();
});

// Handler del evento @dragstart (inicio del drag) y guarda información inicial
const handleDragStart = (event, rowIndex, entryIndex) => {
    draggedRowIndex.value = rowIndex;
    entryRowIndex.value = entryIndex;
    event.dataTransfer.effectAllowed = 'move';
};

// Handler del evento @dragenter (cuando haces drag sobre une elemento y lo arrastras sobre un posible target de drop) y actualiza el targetIndex
const handleDragEnter = (_, targetIndex) => {
    targetRowIndex.value = targetIndex;
};

const saveRowDrop = async (targetRowIndex) => {
    const entryId = draggedEntry.value.id;
    const travelId = rows.value[targetRowIndex].id;
    await axios.patch(`Entries/${entryId}`, { travelFk: travelId });
};

const moveRow = async (draggedRowIndex, targetRowIndex, entryIndex) => {
    try {
        if (draggedRowIndex === targetRowIndex) return;
        // Remover entry de la row original
        draggedEntry.value = rows.value[draggedRowIndex].entries.splice(entryIndex, 1)[0];
        //Si la row de destino por alguna razón no tiene la propiedad entry la creamos
        if (!rows.value[targetRowIndex].entries) rows.value[targetRowIndex].entries = [];
        // Añadir entry a la row de destino
        rows.value[targetRowIndex].entries.push(draggedEntry.value);

        await saveRowDrop(targetRowIndex);
    } catch (err) {
        cleanDragAndDropData();
        console.error('Error moving row', err);
    }
};

// Handler de cuando haces un drop tanto dentro como fuera de la tabla para limpiar acciones y data
const handleDragEnd = () => {
    stopScroll();
    cleanDragAndDropData();
};

// Handler del evento @drop (cuando soltas el elemento draggeado sobre un target)
const handleDrop = () => {
    if (
        !draggedRowIndex.value &&
        draggedRowIndex.value !== 0 &&
        !targetRowIndex.value &&
        draggedRowIndex.value !== 0
    )
        return;
    moveRow(draggedRowIndex.value, targetRowIndex.value, entryRowIndex.value);
    handleDragEnd();
};

const cleanDragAndDropData = () => {
    draggedRowIndex.value = null;
    targetRowIndex.value = null;
    entryRowIndex.value = null;
    draggedEntry.value = null;
};

const scrollInterval = ref(null);

const startScroll = (direction) => {
    // Iniciar el scroll en la dirección especificada
    if (!scrollInterval.value) {
        scrollInterval.value = requestAnimationFrame(() => scroll(direction));
    }
};

const stopScroll = () => {
    if (scrollInterval.value) {
        cancelAnimationFrame(scrollInterval.value);
        scrollInterval.value = null;
    }
};

const scroll = (direction) => {
    // Controlar el desplazamiento en la dirección especificada
    const yOffset = direction === 'up' ? -2 : 2;
    window.scrollBy(0, yOffset);

    const windowHeight = window.innerHeight;
    const documentHeight = document.body.offsetHeight;

    // Verificar si se alcanzaron los límites de la ventana para detener el desplazamiento
    if (
        (direction === 'up' && window.scrollY > 0) ||
        (direction === 'down' && windowHeight + window.scrollY < documentHeight)
    ) {
        scrollInterval.value = requestAnimationFrame(() => scroll(direction));
    } else {
        stopScroll();
    }
};

// Handler del scroll mientras se hace el drag de una row
const handleDragScroll = (event) => {
    // Obtener la posición y dimensiones del cursor
    const y = event.clientY;
    const windowHeight = window.innerHeight;

    // Verificar si el cursor está cerca del borde superior o inferior de la ventana
    const nearTop = y < 150;
    const nearBottom = y > windowHeight - 100;

    if (nearTop) {
        startScroll('up');
    } else if (nearBottom) {
        startScroll('down');
    } else {
        stopScroll();
    }
};

const getColor = (percentage) => {
    for (const { value, className } of travelKgPercentages.value)
        if (percentage > value) return className;
};
</script>

<template>
    <VnSearchbar
        data-key="ExtraCommunity"
        :limit="20"
        :label="t('searchExtraCommunity')"
    />
    <RightMenu>
        <template #right-panel>
            <ExtraCommunityFilter data-key="ExtraCommunity" />
        </template>
    </RightMenu>
    <VnSubToolbar class="justify-end">
        <template #st-actions>
            <QBtn
                color="primary"
                icon-right="picture_as_pdf"
                no-caps
                @click="openReportPdf()"
            >
                <QTooltip>
                    {{ t('Open as PDF') }}
                </QTooltip>
            </QBtn>
        </template>
    </VnSubToolbar>
    <QPage class="column items-center q-pa-md">
        <QTable
            :rows="rows"
            :columns="columns"
            row-key="clientId"
            class="full-width"
            table-style="user-select: none;"
            @drag="handleDragScroll($event)"
            @dragend="handleDragEnd($event)"
            :separator="!targetRowIndex && targetRowIndex !== 0 ? 'horizontal' : 'none'"
        >
            <template #body="props">
                <QTr
                    :props="props"
                    class="cursor-pointer bg-travel"
                    @click="$router.push({ path: `/travel/${props.row.id}` })"
                    @dragenter="handleDragEnter($event, props.rowIndex)"
                    @dragover.prevent
                    @drop="handleDrop()"
                    :class="{
                        'dashed-border --top --left --right':
                            targetRowIndex === props.rowIndex,
                        '--bottom':
                            targetRowIndex === props.rowIndex &&
                            (!props.row.entries || props.row.entries.length === 0),
                    }"
                >
                    <QTd
                        v-for="col in props.cols"
                        :key="col.name"
                        :props="props"
                        @click="stopEventPropagation($event, col)"
                        auto-width
                    >
                        <component
                            :is="tableColumnComponents[col.name].component"
                            v-bind="tableColumnComponents[col.name].attrs"
                            v-model="rows[props.rowIndex][col.field]"
                            v-on="
                                tableColumnComponents[col.name].event
                                    ? tableColumnComponents[col.name].event(
                                          rows[props.rowIndex][col.field],
                                          col.field,
                                          props.rowIndex
                                      )
                                    : {}
                            "
                        >
                            <QChip
                                v-if="col.name === 'percentage'"
                                :label="
                                    props.row.percentageKg
                                        ? `${props.row.percentageKg}%`
                                        : '-'
                                "
                                class="text-left q-py-xs q-px-sm"
                                :color="getColor(props.row.percentageKg)"
                            />
                            <span
                                v-else-if="col.showValue"
                                :class="[
                                    'text-left',
                                    {
                                        'supplier-name':
                                            col.name === 'cargoSupplierNickname',
                                    },
                                    {
                                        link: ['id', 'cargoSupplierNickname'].includes(
                                            col.name
                                        ),
                                    },
                                ]"
                                v-text="col.value"
                            />
                            <!-- Main Row Descriptors -->
                            <TravelDescriptorProxy
                                v-if="col.name === 'id'"
                                :id="props.row.id"
                            />
                            <SupplierDescriptorProxy
                                v-if="col.name === 'cargoSupplierNickname'"
                                :id="props.row.cargoSupplierFk"
                            />
                        </component>
                    </QTd>
                </QTr>

                <QTr
                    v-for="(entry, index) in props.row.entries"
                    :key="index"
                    :props="props"
                    class="bg-vn-secondary-row cursor-pointer"
                    @dragstart="handleDragStart($event, props.rowIndex, index)"
                    @dragenter="handleDragEnter($event, props.rowIndex)"
                    @dragover.prevent
                    @drop="handleDrop()"
                    :draggable="true"
                    :class="{
                        'dragged-row':
                            entryRowIndex === index && props.rowIndex === draggedRowIndex,
                        'dashed-border --left --right': targetRowIndex === props.rowIndex,
                        '--bottom':
                            targetRowIndex === props.rowIndex &&
                            index === props.row.entries.length - 1,
                    }"
                >
                    <QTd>
                        <QBtn flat class="link">{{ entry.id }} </QBtn>
                        <EntryDescriptorProxy :id="entry.id" />
                    </QTd>
                    <QTd>
                        <QBtn flat class="link" dense>{{ entry.supplierName }}</QBtn>
                        <SupplierDescriptorProxy :id="entry.supplierFk" />
                    </QTd>
                    <QTd />
                    <QTd>
                        <span>{{ toCurrency(entry.invoiceAmount) }}</span>
                    </QTd>
                    <QTd>
                        <span>{{ entry.reference }}</span>
                    </QTd>
                    <QTd>
                        <span>{{ entry.stickers }}</span>
                    </QTd>
                    <QTd />
                    <QTd></QTd>
                    <QTd>
                        <span>{{ entry.loadedkg }}</span>
                    </QTd>
                    <QTd>
                        <span>{{ entry.volumeKg }}</span>
                    </QTd>
                    <QTd />
                    <QTd />
                    <QTd />
                    <QTd />
                    <QTd>
                        <QBtn
                            v-if="entry.evaNotes"
                            icon="comment"
                            size="sm"
                            flat
                            color="primary"
                        >
                            <VnPopup
                                :title="t('globals.observations')"
                                :content="entry.evaNotes"
                            />
                        </QBtn>
                    </QTd>
                </QTr>
            </template>
        </QTable>
    </QPage>
</template>

<style scoped lang="scss">
.q-chip {
    color: var(--vn-text-color);
}

:deep(.q-table) {
    border-collapse: collapse;
}

.q-td :deep(input) {
    font-weight: bold;
}

.bg-travel {
    background-color: var(--vn-page-color);
    border-bottom: 2px solid $primary;
}

.dashed-border {
    &.--left {
        border-left: 1px dashed #ccc;
    }

    &.--right {
        border-right: 1px dashed #ccc;
    }

    &.--top {
        border-top: 1px dashed #ccc;
    }

    &.--bottom {
        border-bottom: 1px dashed #ccc;
    }
}

.dragged-row {
    background-color: $primary-light;
}

.supplier-name {
    display: flex;
    max-width: 150px;

    @media (max-width: $breakpoint-md-max) {
        max-width: 100px;
    }
}

.supplier-name-button {
    white-space: normal;
    width: max-content;
}
</style>

<i18n>
en:
    searchExtraCommunity: Search for extra community shipping
    kg: BI. KG
    physicKg: Phy. KG
    shipped: W. shipped
    landed: W. landed

es:
    searchExtraCommunity: Buscar por envío extra comunitario
    kg: KG Bloq.
    physicKg: KG físico
    shipped: F. envío
    landed: F. llegada
    Open as PDF: Abrir como PDF
</i18n>
