<script setup>
import { markRaw, computed } from 'vue';
import { QIcon, QToggle } from 'quasar';
import { dashIfEmpty } from 'src/filters';

import VnSelect from 'components/common/VnSelect.vue';
import VnSelectCache from 'components/common/VnSelectCache.vue';
import VnInput from 'components/common/VnInput.vue';
import VnInputNumber from 'components/common/VnInputNumber.vue';
import VnInputDate from 'components/common/VnInputDate.vue';
import VnInputTime from 'components/common/VnInputTime.vue';
import VnComponent from 'components/common/VnComponent.vue';
import VnUserLink from 'components/ui/VnUserLink.vue';
import VnSelectEnum from '../common/VnSelectEnum.vue';
import VnCheckbox from '../common/VnCheckbox.vue';

const model = defineModel(undefined, { required: true });
const emit = defineEmits(['blur']);
const $props = defineProps({
    column: {
        type: Object,
        required: true,
    },
    row: {
        type: Object,
        default: () => {},
    },
    default: {
        type: [Object, String],
        default: null,
    },
    componentProp: {
        type: String,
        default: null,
    },
    isEditable: {
        type: Boolean,
        default: true,
    },
    components: {
        type: Object,
        default: null,
    },
    autofocus: {
        type: Boolean,
        default: false,
    },
    showLabel: {
        type: Boolean,
        default: null,
    },
    eventHandlers: {
        type: Object,
        default: null,
    },
});

const label = $props.showLabel && $props.column.label ? $props.column.label : '';

const defaultSelect = {
    attrs: {
        row: $props.row,
        disable: !$props.isEditable,
        class: 'fit',
    },
    forceAttrs: {
        label,
    },
};

const defaultComponents = {
    input: {
        component: markRaw(VnInput),
        attrs: {
            disable: !$props.isEditable,
            class: 'fit',
        },
        forceAttrs: {
            label,
        },
    },
    number: {
        component: markRaw(VnInputNumber),
        attrs: {
            disable: !$props.isEditable,
            class: 'fit',
        },
        forceAttrs: {
            label,
        },
    },
    date: {
        component: markRaw(VnInputDate),
        attrs: {
            readonly: !$props.isEditable,
            disable: !$props.isEditable,
            style: 'min-width: 125px',
            class: 'fit',
        },
        forceAttrs: {
            label,
        },
    },
    time: {
        component: markRaw(VnInputTime),
        attrs: {
            disable: !$props.isEditable,
        },
        forceAttrs: {
            label,
        },
    },
    checkbox: {
        ref: 'checkbox',
        component: markRaw(VnCheckbox),
        attrs: ({ model }) => {
            const defaultAttrs = {
                disable: !$props.isEditable,
                'model-value': Boolean(model),
                class: 'no-padding fit',
            };

            if (typeof model == 'number') {
                defaultAttrs['true-value'] = 1;
                defaultAttrs['false-value'] = 0;
            }
            return defaultAttrs;
        },
        forceAttrs: {
            label,
            autofocus: true,
        },
        events: {
            blur: () => emit('blur'),
        },
    },
    select: {
        component: markRaw(VnSelectCache),
        ...defaultSelect,
    },
    rawSelect: {
        component: markRaw(VnSelect),
        ...defaultSelect,
    },
    selectEnum: {
        component: markRaw(VnSelectEnum),
        ...defaultSelect,
    },
    icon: {
        component: markRaw(QIcon),
    },
    userLink: {
        component: markRaw(VnUserLink),
    },
    toggle: {
        component: markRaw(QToggle),
    },
};

const value = computed(() => {
    return $props.column.format
        ? $props.column.format($props.row, dashIfEmpty)
        : dashIfEmpty($props.row[$props.column.name]);
});

const col = computed(() => {
    let newColumn = { ...$props.column };
    const specific = newColumn[$props.componentProp];
    if (specific) {
        newColumn = {
            ...newColumn,
            ...specific,
            ...specific.attrs,
            ...specific.forceAttrs,
        };
    }
    if (
        (/^is[A-Z]/.test(newColumn.name) || /^has[A-Z]/.test(newColumn.name)) &&
        newColumn.component == null
    )
        newColumn.component = 'checkbox';
    if ($props.default && !newColumn.component) newColumn.component = $props.default;

    return newColumn;
});

const components = computed(() => {
    const sourceComponents = $props.components ?? defaultComponents;

    return Object.keys(sourceComponents).reduce((acc, key) => {
        const component = sourceComponents[key];

        if (!component || typeof component !== 'object') {
            acc[key] = component;
            return acc;
        }

        acc[key] = {
            ...component,
            attrs: {
                ...(component.attrs || {}),
                autofocus: $props.autofocus,
            },
            event: { ...component?.event, ...$props?.eventHandlers },
        };
        return acc;
    }, {});
});
</script>
<template>
    <div class="row no-wrap">
        <VnComponent
            v-if="col.before"
            :prop="col.before"
            :components="components"
            :value="{ row, model }"
            v-model="model"
        />
        <VnComponent
            v-if="col.component"
            :prop="col"
            :components="components"
            :value="{ row, model }"
            v-model="model"
        />
        <span :title="value" v-else>{{ value }}</span>
        <VnComponent
            v-if="col.after"
            :prop="col.after"
            :components="components"
            :value="{ row, model }"
            v-model="model"
        />
    </div>
</template>
