<script setup>
import {
    ref,
    onBeforeMount,
    onMounted,
    onUnmounted,
    computed,
    watch,
    h,
    render,
    inject,
    useAttrs,
    nextTick,
} from 'vue';
import { useArrayData } from 'src/composables/useArrayData';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { useQuasar, date } from 'quasar';
import { useStateStore } from 'stores/useStateStore';
import { useFilterParams } from 'src/composables/useFilterParams';
import { dashIfEmpty, toDate } from 'src/filters';

import CrudModel from 'src/components/CrudModel.vue';
import FormModelPopup from 'components/FormModelPopup.vue';

import VnColumn from 'components/VnTable/VnColumn.vue';
import VnFilter from 'components/VnTable/VnFilter.vue';
import VnTableChip from 'components/VnTable/VnChip.vue';
import VnVisibleColumn from 'src/components/VnTable/VnVisibleColumn.vue';
import VnLv from 'components/ui/VnLv.vue';
import VnTableOrder from 'src/components/VnTable/VnOrder.vue';
import VnTableFilter from './VnTableFilter.vue';
import { getColAlign } from 'src/composables/getColAlign';
import RightMenu from '../common/RightMenu.vue';

const arrayData = useArrayData(useAttrs()['data-key']);
const $props = defineProps({
    columns: {
        type: Array,
        required: true,
    },
    defaultMode: {
        type: String,
        default: 'table', // 'table', 'card'
    },
    columnSearch: {
        type: Boolean,
        default: true,
    },
    rightSearch: {
        type: Boolean,
        default: true,
    },
    rowClick: {
        type: [Function, Boolean],
        default: null,
    },
    rowCtrlClick: {
        type: [Function, Boolean],
        default: null,
    },
    redirect: {
        type: String,
        default: null,
    },
    create: {
        type: Object,
        default: null,
    },
    createAsDialog: {
        type: Boolean,
        default: true,
    },
    bottom: {
        type: Boolean,
        default: false,
    },
    cardClass: {
        type: String,
        default: 'flex-one',
    },
    searchUrl: {
        type: [String, Boolean],
        default: 'table',
    },
    isEditable: {
        type: Boolean,
        default: false,
    },
    useModel: {
        type: Boolean,
        default: false,
    },
    hasSubToolbar: {
        type: Boolean,
        default: null,
    },
    disableOption: {
        type: Object,
        default: () => ({ card: false, table: false }),
    },
    withoutHeader: {
        type: Boolean,
        default: false,
    },
    tableCode: {
        type: String,
        default: null,
    },
    table: {
        type: Object,
        default: () => ({}),
    },
    crudModel: {
        type: Object,
        default: () => ({}),
    },
    tableHeight: {
        type: String,
        default: '90vh',
    },
    footer: {
        type: Boolean,
        default: false,
    },
    disabledAttr: {
        type: Boolean,
        default: false,
    },
    withFilters: {
        type: Boolean,
        default: true,
    },
    overlay: {
        type: Boolean,
        default: false,
    },
    createComplement: {
        type: Object,
    },
    dataCy: {
        type: String,
        default: 'vnTable',
    },
});

const { t } = useI18n();
const stateStore = useStateStore();
const route = useRoute();
const router = useRouter();
const quasar = useQuasar();
const $attrs = useAttrs();

const CARD_MODE = 'card';
const TABLE_MODE = 'table';
const mode = ref(CARD_MODE);
const selected = ref([]);
const hasParams = ref(false);
const CrudModelRef = ref({});
const showForm = ref(false);
const splittedColumns = ref({ columns: [] });
const columnsVisibilitySkipped = ref();
const createForm = ref();
const createRef = ref(null);
const tableRef = ref();
const params = ref(useFilterParams($attrs['data-key']).params);
const orders = ref(useFilterParams($attrs['data-key']).orders);
const app = inject('app');

const editingRow = ref(null);
const editingField = ref(null);
const isTableMode = computed(() => mode.value == TABLE_MODE);
const selectRegex = /select/;
const emit = defineEmits(['onFetch', 'update:selected', 'saveChanges']);
const tableModes = [
    {
        icon: 'view_column',
        title: t('table view'),
        value: TABLE_MODE,
        disable: $props.disableOption?.table,
    },
    {
        icon: 'grid_view',
        title: t('grid view'),
        value: CARD_MODE,
        disable: $props.disableOption?.card,
    },
];

onBeforeMount(() => {
    const urlParams = route.query[$props.searchUrl];
    hasParams.value = urlParams && Object.keys(urlParams).length !== 0;
});

onMounted(async () => {
    if ($props.isEditable) document.addEventListener('click', clickHandler);
    mode.value =
        quasar.platform.is.mobile && !$props.disableOption?.card
            ? CARD_MODE
            : $props.defaultMode;
    stateStore.rightDrawer = quasar.screen.gt.xs;
    columnsVisibilitySkipped.value = [
        ...splittedColumns.value.columns
            .filter((c) => c.visible === false)
            .map((c) => c.name),
        ...['tableActions'],
    ];
    createForm.value = $props.create;
    if ($props.create && route?.query?.createForm) {
        showForm.value = true;
        createForm.value = {
            ...createForm.value,
            ...{ formInitialData: JSON.parse(route?.query?.createForm) },
        };
    }
});

onUnmounted(async () => {
    if ($props.isEditable) document.removeEventListener('click', clickHandler);
});

watch(
    () => $props.columns,
    (value) => splitColumns(value),
    { immediate: true },
);

defineExpose({
    create: createForm,
    reload,
    redirect: redirectFn,
    selected,
    CrudModelRef,
    params,
    tableRef,
});

function splitColumns(columns) {
    splittedColumns.value = {
        columns: [],
        chips: [],
        create: [],
        cardVisible: [],
    };

    for (const col of columns) {
        if (col.name == 'tableActions') {
            col.orderBy = false;
            splittedColumns.value.actions = col;
        }
        if (col.chip) splittedColumns.value.chips.push(col);
        if (col.isTitle) splittedColumns.value.title = col;
        if (col.create) splittedColumns.value.create.push(col);
        if (col.cardVisible) splittedColumns.value.cardVisible.push(col);
        if ($props.isEditable && col.disable == null) col.disable = false;
        if ($props.useModel && col.columnFilter !== false)
            col.columnFilter = { inWhere: true, ...col.columnFilter };
        splittedColumns.value.columns.push(col);
    }

    splittedColumns.value.create = createOrderSort(splittedColumns.value.create);

    if (splittedColumns.value.chips.length) {
        splittedColumns.value.columnChips = splittedColumns.value.chips.filter(
            (c) => !c.isId,
        );
        if (splittedColumns.value.columnChips.length)
            splittedColumns.value.columns.unshift({
                align: 'left',
                label: t('status'),
                name: 'tableStatus',
                columnFilter: false,
                orderBy: false,
            });
    }
}

function createOrderSort(columns) {
    const orderedColumn = columns
        .map((column, index) =>
            column.createOrder !== undefined ? { ...column, originalIndex: index } : null,
        )
        .filter((item) => item !== null);

    orderedColumn.sort((a, b) => a.createOrder - b.createOrder);

    const filteredColumns = columns.filter((col) => col.createOrder === undefined);

    orderedColumn.forEach((col) => {
        filteredColumns.splice(col.createOrder, 0, col);
    });

    return filteredColumns;
}

const rowClickFunction = computed(() => {
    if ($props.rowClick != undefined) return $props.rowClick;
    if ($props.redirect) return ({ id }) => redirectFn(id);
    return () => {};
});

function redirectFn(id) {
    router.push({ path: `/${$props.redirect}/${id}` });
}

function stopEventPropagation(event) {
    event.preventDefault();
    event.stopPropagation();
}

function reload(params) {
    selected.value = [];
    CrudModelRef.value.reload(params);
}

function columnName(col) {
    const column = { ...col, ...col.columnFilter };
    let name = column.name;
    if (column.alias) name = column.alias + '.' + name;
    return name;
}

function handleOnDataSaved(_) {
    if (_.onDataSaved) _.onDataSaved({ CrudModelRef: CrudModelRef.value });
    else $props.create.onDataSaved(_);
}

function handleScroll() {
    if ($props.crudModel.disableInfiniteScroll) return;

    const tMiddle = tableRef.value.$el.querySelector('.q-table__middle');
    const { scrollHeight, scrollTop, clientHeight } = tMiddle;
    const isAtBottom = Math.abs(scrollHeight - scrollTop - clientHeight) <= 40;
    if (isAtBottom) CrudModelRef.value.vnPaginateRef.paginate();
}

function handleSelection({ evt, added, rows: selectedRows }, rows) {
    if (evt?.shiftKey && added) {
        const rowIndex = selectedRows[0].$index;
        const selectedIndexes = new Set(selected.value.map((row) => row.$index));
        const minIndex = selectedIndexes.size
            ? Math.min(...selectedIndexes, rowIndex)
            : 0;
        const maxIndex = Math.max(...selectedIndexes, rowIndex);

        for (let i = minIndex; i <= maxIndex; i++) {
            const row = rows[i];
            if (row.$index == rowIndex) continue;
            if (!selectedIndexes.has(row.$index)) {
                selected.value.push(row);
                selectedIndexes.add(row.$index);
            }
        }
    }
}

function isEditableColumn(column) {
    const isEditableCol = column?.isEditable ?? true;
    const isVisible = column?.visible ?? true;
    const hasComponent = column?.component;

    return $props.isEditable && isVisible && hasComponent && isEditableCol;
}

function hasEditableFormat(column) {
    if (isEditableColumn(column)) return 'editable-text';
}

const clickHandler = async (event) => {
    const clickedElement = event.target.closest('td');
    const isDateElement = event.target.closest('.q-date');
    const isTimeElement = event.target.closest('.q-time');
    const isQSelectDropDown = event.target.closest('.q-select__dropdown-icon');

    if (isDateElement || isTimeElement || isQSelectDropDown) return;

    if (clickedElement === null) {
        await destroyInput(editingRow.value, editingField.value);
        return;
    }
    const rowIndex = clickedElement.getAttribute('data-row-index');
    const colField = clickedElement.getAttribute('data-col-field');
    const column = $props.columns.find((col) => col.name === colField);

    if (editingRow.value !== null && editingField.value !== null) {
        if (editingRow.value == rowIndex && editingField.value == colField) return;

        await destroyInput(editingRow.value, editingField.value);
    }

    if (isEditableColumn(column)) {
        await renderInput(Number(rowIndex), colField, clickedElement);
    }
};

async function handleTabKey(event, rowIndex, colField) {
    if (editingRow.value == rowIndex && editingField.value == colField)
        await destroyInput(editingRow.value, editingField.value);

    const direction = event.shiftKey ? -1 : 1;
    const { nextRowIndex, nextColumnName } = await handleTabNavigation(
        rowIndex,
        colField,
        direction,
    );

    if (nextRowIndex < 0 || nextRowIndex >= arrayData.store.data.length) return;

    event.preventDefault();
    await renderInput(nextRowIndex, nextColumnName, null);
}

async function renderInput(rowId, field, clickedElement) {
    editingField.value = field;
    editingRow.value = rowId;

    const originalColumn = $props.columns.find((col) => col.name === field);
    const column = { ...originalColumn, ...{ label: '' } };
    const row = CrudModelRef.value.formData[rowId];
    const oldValue = CrudModelRef.value.formData[rowId][column?.name];

    if (!clickedElement)
        clickedElement = document.querySelector(
            `[data-row-index="${rowId}"][data-col-field="${field}"]`,
        );

    Array.from(clickedElement.childNodes).forEach((child) => {
        child.style.visibility = 'hidden';
        child.style.position = 'relative';
    });

    const isSelect = selectRegex.test(column?.component);
    if (isSelect) column.attrs = { ...column.attrs, 'emit-value': false };

    const node = h(VnColumn, {
        row: row,
        class: 'temp-input',
        column: column,
        modelValue: row[column.name],
        componentProp: 'columnField',
        autofocus: true,
        focusOnMount: true,
        eventHandlers: {
            'update:modelValue': async (value) => {
                if (isSelect && value) {
                    await updateSelectValue(value, column, row, oldValue);
                } else row[column.name] = value;
                await column?.cellEvent?.['update:modelValue']?.(value, oldValue, row);
            },
            keyup: async (event) => {
                if (event.key === 'Enter')
                    await destroyInput(rowId, field, clickedElement);
            },
            keydown: async (event) => {
                switch (event.key) {
                    case 'Tab':
                        await handleTabKey(event, rowId, field);
                        event.stopPropagation();
                        break;
                    case 'Escape':
                        await destroyInput(rowId, field, clickedElement);
                        break;
                    default:
                        break;
                }
            },
            click: (event) => {
                column?.cellEvent?.['click']?.(event, row);
            },
        },
    });

    node.appContext = app._context;
    render(node, clickedElement);

    if (['toggle'].includes(column?.component))
        node.el?.querySelector('span > div').focus();

    if (['checkbox', undefined].includes(column?.component))
        node.el?.querySelector('span > div > div').focus();
}

async function updateSelectValue(value, column, row, oldValue) {
    row[column.name] = value[column.attrs?.optionValue ?? 'id'];

    row[column?.name + 'VnTableTextValue'] = value[column.attrs?.optionLabel ?? 'name'];

    if (column?.attrs?.find?.label)
        row[column?.attrs?.find?.label] = value[column.attrs?.optionLabel ?? 'name'];

    await column?.cellEvent?.['update:modelValue']?.(value, oldValue, row);
}

async function destroyInput(rowIndex, field, clickedElement) {
    if (!clickedElement)
        clickedElement = document.querySelector(
            `[data-row-index="${rowIndex}"][data-col-field="${field}"]`,
        );
    if (clickedElement) {
        await nextTick();
        render(null, clickedElement);
        Array.from(clickedElement.childNodes).forEach((child) => {
            child.style.visibility = 'visible';
            child.style.position = '';
        });
    }
    if (editingRow.value !== rowIndex || editingField.value !== field) return;
    editingRow.value = null;
    editingField.value = null;
}

async function handleTabNavigation(rowIndex, colName, direction) {
    const columns = $props.columns;
    const totalColumns = columns.length;
    let currentColumnIndex = columns.findIndex((col) => col.name === colName);

    let iterations = 0;
    let newColumnIndex = currentColumnIndex;

    do {
        iterations++;
        newColumnIndex = (newColumnIndex + direction + totalColumns) % totalColumns;

        if (isEditableColumn(columns[newColumnIndex])) break;
    } while (iterations < totalColumns);

    if (iterations >= totalColumns + 1) return;

    if (direction === 1 && newColumnIndex <= currentColumnIndex) {
        rowIndex++;
    } else if (direction === -1 && newColumnIndex >= currentColumnIndex) {
        rowIndex--;
    }
    return { nextRowIndex: rowIndex, nextColumnName: columns[newColumnIndex].name };
}

function getCheckboxIcon(value) {
    switch (typeof value) {
        case 'boolean':
            return value ? 'check' : 'close';
        case 'number':
            return value === 0 ? 'close' : 'check';
        case 'undefined':
            return 'indeterminate_check_box';
        default:
            return 'indeterminate_check_box';
    }
}

function getToggleIcon(value) {
    if (value === null) return 'help_outline';
    return value ? 'toggle_on' : 'toggle_off';
}

function formatColumnValue(col, row, dashIfEmpty) {
    if (col?.format || row[col?.name + 'VnTableTextValue']) {
        if (selectRegex.test(col?.component) && row[col?.name + 'VnTableTextValue']) {
            return dashIfEmpty(row[col?.name + 'VnTableTextValue']);
        } else {
            return col.format(row, dashIfEmpty);
        }
    }

    if (col?.component === 'date') return dashIfEmpty(toDate(row[col?.name]));

    if (col?.component === 'time')
        return row[col?.name] >= 5
            ? dashIfEmpty(date.formatDate(new Date(row[col?.name]), 'HH:mm'))
            : row[col?.name];

    if (selectRegex.test(col?.component) && $props.isEditable) {
        const { find, url } = col.attrs;
        const urlRelation = url?.charAt(0)?.toLocaleLowerCase() + url?.slice(1, -1);

        if (col?.attrs.options) {
            const find = col?.attrs.options.find((option) => option.id === row[col.name]);
            if (!col.attrs?.optionLabel || !find) return dashIfEmpty(row[col?.name]);
            return dashIfEmpty(find[col.attrs?.optionLabel ?? 'name']);
        }

        if (typeof row[urlRelation] == 'object') {
            if (typeof find == 'object')
                return dashIfEmpty(row[urlRelation][find?.label ?? 'name']);

            return dashIfEmpty(row[urlRelation][col?.attrs.optionLabel ?? 'name']);
        }
        if (typeof row[urlRelation] == 'string') return dashIfEmpty(row[urlRelation]);
    }
    return dashIfEmpty(row[col?.name]);
}

function cardClick(_, row) {
    if ($props.redirect) router.push({ path: `/${$props.redirect}/${row.id}` });
}

function removeTextValue(data, getChanges) {
    let changes = data.updates;
    if (changes) {
        for (const change of changes) {
            for (const key in change.data) {
                if (key.endsWith('VnTableTextValue')) {
                    delete change.data[key];
                }
            }
        }

        data.updates = changes.filter((change) => Object.keys(change.data).length > 0);
    }
    if ($attrs?.beforeSaveFn) data = $attrs.beforeSaveFn(data, getChanges);

    return data;
}

function handleRowClick(event, row) {
    if (event.ctrlKey) return rowCtrlClickFunction.value(event, row);
    if (rowClickFunction.value) rowClickFunction.value(row);
}

const rowCtrlClickFunction = computed(() => {
    if ($props.rowCtrlClick != undefined) return $props.rowCtrlClick;
    if ($props.redirect)
        return (evt, { id }) => {
            stopEventPropagation(evt);
            window.open(`/#/${$props.redirect}/${id}`, '_blank');
        };
    return () => {};
});
</script>
<template>
    <RightMenu v-if="$props.rightSearch" :overlay="overlay">
        <template #right-panel>
            <VnTableFilter
                :data-key="$attrs['data-key']"
                :columns="columns"
                :redirect="redirect"
                v-bind="$attrs?.['table-filter']"
            >
                <template
                    v-for="(_, slotName) in $slots"
                    #[slotName]="slotData"
                    :key="slotName"
                >
                    <slot :name="slotName" v-bind="slotData ?? {}" :key="slotName" />
                </template>
            </VnTableFilter>
        </template>
    </RightMenu>
    <CrudModel
        v-bind="$attrs"
        :class="$attrs['class'] ?? 'q-px-md'"
        :limit="$attrs['limit'] ?? 100"
        ref="CrudModelRef"
        @on-fetch="(...args) => emit('onFetch', ...args)"
        :search-url="searchUrl"
        :disable-infinite-scroll="isTableMode"
        :before-save-fn="removeTextValue"
        @save-changes="reload"
        :has-sub-toolbar="$props.hasSubToolbar ?? isEditable"
        :auto-load="hasParams || $attrs['auto-load']"
    >
        <template v-for="(_, slotName) in $slots" #[slotName]="slotData" :key="slotName">
            <slot :name="slotName" v-bind="slotData ?? {}" :key="slotName" />
        </template>
        <template #body="{ rows }">
            <QTable
                ref="tableRef"
                v-bind="table"
                :class="[
                    'vnTable',
                    table ? 'selection-cell' : '',
                    $props.footer ? 'last-row-sticky' : '',
                ]"
                wrap-cells
                :columns="splittedColumns.columns"
                :rows="rows"
                v-model:selected="selected"
                :grid="!isTableMode"
                table-header-class="bg-header"
                card-container-class="grid-three"
                flat
                :style="isTableMode && `max-height: ${tableHeight}`"
                :virtual-scroll="isTableMode"
                @virtual-scroll="handleScroll"
                @row-click="(event, row) => handleRowClick(event, row)"
                @update:selected="emit('update:selected', $event)"
                @selection="(details) => handleSelection(details, rows)"
                :hide-selected-banner="true"
                :data-cy
            >
                <template #top-left v-if="!$props.withoutHeader">
                    <slot name="top-left"> </slot>
                </template>
                <template #top-right v-if="!$props.withoutHeader">
                    <slot name="top-right"></slot>
                    <VnVisibleColumn
                        v-if="isTableMode"
                        v-model="splittedColumns.columns"
                        :table-code="tableCode ?? route.name"
                        :skip="columnsVisibilitySkipped"
                    />
                    <QBtnToggle
                        v-if="!tableModes.some((mode) => mode.disable)"
                        v-model="mode"
                        toggle-color="primary"
                        class="bg-vn-section-color"
                        dense
                        :options="tableModes.filter((mode) => !mode.disable)"
                    />
                </template>
                <template #header-cell="{ col }">
                    <QTh
                        v-if="col.visible ?? true"
                        v-bind:class="col.headerClass"
                        class="body-cell"
                        :style="col?.width ? `max-width: ${col?.width}` : ''"
                    >
                        <div
                            class="no-padding"
                            :style="[
                                withFilters && $props.columnSearch ? 'height: 75px' : '',
                            ]"
                        >
                            <div style="height: 30px">
                                <QTooltip v-if="col.toolTip">{{ col.toolTip }}</QTooltip>
                                <VnTableOrder
                                    v-model="orders[col.orderBy ?? col.name]"
                                    :name="col.orderBy ?? col.name"
                                    :label="col?.labelAbbreviation ?? col?.label"
                                    :data-key="$attrs['data-key']"
                                    :search-url="searchUrl"
                                    :align="getColAlign(col)"
                                />
                            </div>
                            <VnFilter
                                v-if="
                                    $props.columnSearch &&
                                    col.columnSearch !== false &&
                                    withFilters
                                "
                                :column="col"
                                :show-title="true"
                                :data-key="$attrs['data-key']"
                                v-model="params[columnName(col)]"
                                :search-url="searchUrl"
                                customClass="header-filter"
                            />
                        </div>
                    </QTh>
                </template>
                <template #header-cell-tableActions>
                    <QTh auto-width class="sticky" />
                </template>
                <template #body-cell-tableStatus="{ col, row }">
                    <QTd auto-width :class="getColAlign(col)">
                        <VnTableChip :columns="splittedColumns.columnChips" :row="row">
                            <template #afterChip>
                                <slot name="afterChip" :row="row"></slot>
                            </template>
                        </VnTableChip>
                    </QTd>
                </template>
                <template #body-cell="{ col, row, rowIndex }">
                    <QTd
                        class="no-margin q-px-xs"
                        v-if="col.visible ?? true"
                        :style="{
                            'max-width': col?.width ?? false,
                            position: 'relative',
                        }"
                        :class="[
                            col.columnClass,
                            'body-cell no-margin no-padding',
                            getColAlign(col),
                        ]"
                        :data-row-index="rowIndex"
                        :data-col-field="col?.name"
                    >
                        <div
                            class="no-padding no-margin"
                            style="
                                overflow: hidden;
                                text-overflow: ellipsis;
                                white-space: nowrap;
                            "
                            :data-cy="`vnTableCell_${col.name}`"
                        >
                            <slot
                                :name="`column-${col.name}`"
                                :col="col"
                                :row="row"
                                :row-index="rowIndex"
                            >
                                <QIcon
                                    v-if="col?.component === 'toggle'"
                                    :name="
                                        col?.getIcon
                                            ? col.getIcon(row[col?.name])
                                            : getToggleIcon(row[col?.name])
                                    "
                                    style="color: var(--vn-text-color)"
                                    :class="hasEditableFormat(col)"
                                    size="14px"
                                />
                                <QIcon
                                    v-else-if="col?.component === 'checkbox'"
                                    :name="getCheckboxIcon(row[col?.name])"
                                    style="color: var(--vn-text-color)"
                                    :class="hasEditableFormat(col)"
                                    size="14px"
                                />
                                <span
                                    v-else
                                    :class="hasEditableFormat(col)"
                                    :style="
                                        typeof col?.style == 'function'
                                            ? col.style(row)
                                            : col?.style
                                    "
                                    style="bottom: 0"
                                >
                                    {{ formatColumnValue(col, row, dashIfEmpty) }}
                                </span>
                            </slot>
                        </div>
                    </QTd>
                </template>
                <template #body-cell-tableActions="{ col, row }">
                    <QTd
                        auto-width
                        :class="getColAlign(col)"
                        class="sticky no-padding"
                        @click="stopEventPropagation($event)"
                        :style="col.style"
                    >
                        <QBtn
                            v-for="(btn, index) of col.actions"
                            v-show="btn.show ? btn.show(row) : true"
                            :key="index"
                            :title="btn.title"
                            :icon="btn.icon"
                            class="q-pa-xs"
                            flat
                            dense
                            :class="
                                btn.isPrimary ? 'text-primary-light' : 'color-vn-label'
                            "
                            :style="`visibility: ${
                                ((btn.show && btn.show(row)) ?? true)
                                    ? 'visible'
                                    : 'hidden'
                            }`"
                            @click="btn.action(row)"
                            :data-cy="btn?.name ?? `tableAction-${index}`"
                        />
                    </QTd>
                </template>
                <template #item="{ row, colsMap }">
                    <component
                        v-bind:is="'div'"
                        @click="(event) => cardClick(event, row)"
                    >
                        <QCard
                            bordered
                            flat
                            class="row no-wrap justify-between cursor-pointer q-pa-sm"
                            style="height: 100%"
                        >
                            <QCardSection
                                vertical
                                class="no-margin no-padding"
                                :class="colsMap.tableActions ? 'w-80' : 'fit'"
                            >
                                <!-- Chips -->
                                <QCardSection
                                    v-if="splittedColumns.chips.length"
                                    class="no-margin q-px-xs q-py-none"
                                >
                                    <VnTableChip
                                        :columns="splittedColumns.chips"
                                        :row="row"
                                    >
                                        <template #afterChip>
                                            <slot name="afterChip" :row="row"></slot>
                                        </template>
                                    </VnTableChip>
                                </QCardSection>
                                <!-- Title -->
                                <QCardSection
                                    v-if="splittedColumns.title"
                                    class="q-pl-sm q-py-none text-primary-light text-bold text-h6 cardEllipsis"
                                >
                                    <span
                                        :title="row[splittedColumns.title.name]"
                                        @click="stopEventPropagation($event)"
                                        class="cursor-text"
                                    >
                                        {{ row[splittedColumns.title.name] }}
                                    </span>
                                </QCardSection>
                                <!-- Fields  -->
                                <QCardSection
                                    class="q-pl-sm q-py-xs"
                                    :class="$props.cardClass"
                                >
                                    <div
                                        v-for="(
                                            col, index
                                        ) of splittedColumns.cardVisible"
                                        :key="col.name"
                                        class="fields"
                                    >
                                        <VnLv :label="col.label + ':'">
                                            <template #value>
                                                <span
                                                    @click="stopEventPropagation($event)"
                                                >
                                                    <slot
                                                        :name="`column-${col.name}`"
                                                        :col="col"
                                                        :row="row"
                                                        :row-index="index"
                                                    >
                                                        <VnColumn
                                                            :column="{
                                                                ...col,
                                                                disable:
                                                                    col?.component ===
                                                                    'checkbox'
                                                                        ? true
                                                                        : false,
                                                            }"
                                                            :row="row"
                                                            :is-editable="false"
                                                            v-model="row[col.name]"
                                                            component-prop="columnField"
                                                            :show-label="
                                                                col?.component ===
                                                                'checkbox'
                                                                    ? false
                                                                    : true
                                                            "
                                                        />
                                                    </slot>
                                                </span>
                                            </template>
                                        </VnLv>
                                    </div>
                                </QCardSection>
                            </QCardSection>
                            <!-- Actions -->
                            <QCardSection
                                v-if="colsMap.tableActions"
                                @click="stopEventPropagation($event)"
                            >
                                <QBtn
                                    v-for="(btn, index) of splittedColumns.actions
                                        .actions"
                                    :key="index"
                                    :title="btn.title"
                                    :icon="btn.icon"
                                    data-cy="cardBtn"
                                    class="q-pa-xs"
                                    :class="
                                        btn.isPrimary
                                            ? 'text-primary-light'
                                            : 'color-vn-label'
                                    "
                                    flat
                                    @click="btn.action(row)"
                                />
                            </QCardSection>
                        </QCard>
                    </component>
                </template>
                <template #bottom-row="{ cols }" v-if="$props.footer">
                    <QTr v-if="rows.length" style="height: 45px">
                        <QTh v-if="table.selection" />
                        <QTh
                            v-for="col of cols.filter((cols) => cols.visible ?? true)"
                            :key="col?.id"
                            :class="getColAlign(col)"
                            :style="col?.width ? `max-width: ${col?.width}` : ''"
                            style="font-size: small"
                        >
                            <slot
                                :name="`column-footer-${col.name}`"
                                :isEditableColumn="isEditableColumn(col)"
                            />
                        </QTh>
                    </QTr>
                </template>
            </QTable>
            <div class="full-width bottomButton" v-if="bottom">
                <QBtn
                    @click="
                        () =>
                            createAsDialog
                                ? (showForm = !showForm)
                                : handleOnDataSaved(create)
                    "
                    class="cursor-pointer fill-icon"
                    color="primary"
                    icon="add_circle"
                    size="md"
                    round
                    flat
                    v-shortcut="'+'"
                    :disabled="!disabledAttr"
                />
                <QTooltip>
                    {{ createForm.title }}
                </QTooltip>
            </div>
        </template>
    </CrudModel>
    <QPageSticky v-if="$props.create" :offset="[20, 20]" style="z-index: 2">
        <QBtn
            @click="
                () =>
                    createAsDialog ? (showForm = !showForm) : handleOnDataSaved(create)
            "
            color="primary"
            fab
            icon="add"
            v-shortcut="'+'"
            data-cy="vnTableCreateBtn"
        />
        <QTooltip self="top right">
            {{ createForm?.title }}
        </QTooltip>
    </QPageSticky>
    <QDialog
        v-model="showForm"
        transition-show="scale"
        transition-hide="scale"
        :full-width="createComplement?.isFullWidth ?? false"
        data-cy="vn-table-create-dialog"
    >
        <FormModelPopup
            ref="createRef"
            v-bind="createForm"
            :model="$attrs['data-key'] + 'Create'"
            @on-data-saved="(_, res) => createForm.onDataSaved(res)"
        >
            <template #form-inputs="{ data }">
                <slot name="alter-create" :data="data">
                    <div :style="createComplement?.containerStyle">
                        <div
                            :style="createComplement?.previousStyle"
                            v-if="!quasar.screen.xs"
                        >
                            <slot name="previous-create-dialog" :data="data" />
                        </div>
                        <div
                            class="grid-create"
                            :style="createComplement?.columnGridStyle"
                        >
                            <slot
                                v-for="column of splittedColumns.create"
                                :key="column.name"
                                :name="`column-create-${column.name}`"
                                :data="data"
                                :column-name="column.name"
                                :label="column.label"
                            >
                                <VnColumn
                                    :column="{
                                        ...column,
                                        ...column?.createAttrs,
                                    }"
                                    :row="{}"
                                    default="input"
                                    v-model="data[column.name]"
                                    :show-label="true"
                                    component-prop="columnCreate"
                                    :data-cy="`${column.name}-create-popup`"
                                />
                            </slot>
                            <slot name="more-create-dialog" :data="data" />
                        </div>
                    </div>
                </slot>
            </template>
        </FormModelPopup>
    </QDialog>
</template>
<i18n>
en:
    status: Status
    table view: Table view
    grid view: Grid view
es:
    status: Estados
    table view: Vista en tabla
    grid view: Vista en cuadrícula
</i18n>

<style lang="scss">
.selection-cell {
    table td:first-child {
        padding: 0px;
    }
}
.side-padding {
    padding-left: 1px;
    padding-right: 1px;
}
.editable-text:hover {
    border-bottom: 1px dashed var(--q-primary);
    @extend .side-padding;
}
.editable-text {
    border-bottom: 1px dashed var(--vn-label-color);
    @extend .side-padding;
}
.cell-input {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    padding-top: 0px !important;
}
.q-field--labeled .q-field__native,
.q-field--labeled .q-field__prefix,
.q-field--labeled .q-field__suffix {
    padding-top: 20px;
}

.body-cell {
    padding-left: 4px !important;
    padding-right: 4px !important;
    position: relative;
}
.bg-chip-secondary {
    background-color: var(--vn-page-color);
    color: var(--vn-text-color);
}

.bg-header {
    background-color: var(--vn-accent-color);
    color: var(--vn-text-color);
}

.color-vn-text {
    color: var(--vn-text-color);
}

.grid-three {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, max-content));
    width: 100%;
    grid-gap: 20px;
    margin: 0 auto;
}

.grid-create {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, max-content));
    max-width: 100%;
    grid-gap: 20px;
    margin: 0 auto;
    .col-span-2 {
        grid-column: span 2;
    }
}

.flex-one {
    display: flex;
    flex-flow: row wrap;
    div.fields {
        width: 100%;
        .vn-label-value {
            display: flex;
            gap: 2%;
        }
    }
}
.q-table tbody tr td {
    position: relative;
}
.q-table {
    th {
        padding: 0;
    }

    &__top {
        padding: 12px 0px;
        top: 0;
    }
}

.vnTable {
    thead tr th {
        position: sticky;
        z-index: 2;
    }
    thead tr:first-child th {
        top: 0;
    }
    .q-table__top {
        top: 0;
        padding: 12px 0;
    }
    .sticky {
        position: sticky;
        right: 0;
    }
    td.sticky {
        background-color: var(--vn-section-color);
        z-index: 1;
    }
    table tbody th {
        position: relative;
    }
}

.last-row-sticky {
    tbody:nth-last-child(1) {
        @extend .bg-header;
        position: sticky;
        z-index: 2;
        bottom: 0;
    }
}

.vn-label-value {
    display: flex;
    flex-direction: row;
    align-items: center;
    color: var(--vn-text-color);
    .value {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        pointer-events: all;
        cursor: text;
        user-select: all;
    }
}

.cardEllipsis {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.grid-two {
    display: grid;
    grid-template-columns: 2fr 2fr;
    .vn-label-value {
        flex-direction: column;
        white-space: nowrap;
        .fields {
            display: flex;
        }
    }
    white-space: nowrap;
}

.w-80 {
    width: 80%;
}

.w-20 {
    width: 20%;
}

.cursor-text {
    pointer-events: all;
    cursor: text;
    user-select: all;
}

.q-table__container {
    background-color: transparent;
}

.q-table__middle.q-virtual-scroll.q-virtual-scroll--vertical.scroll {
    background-color: var(--vn-section-color);
}
.temp-input {
    top: 0;
    position: absolute;
    width: 100%;
    height: 100%;
    display: flex;
}

label.header-filter > .q-field__inner > .q-field__control {
    padding: inherit;
}
</style>
