<script setup>
import {computed, h, reactive, ref, watch} from "vue";
import {
    NButton,
    NDataTable,
    NDatePicker,
    NEllipsis,
    NForm,
    NFormItem,
    NIcon,
    NModal,
    NPopconfirm,
    NSelect,
    NSpin,
    NText,
} from "naive-ui";
import {TbPencil, TbTrash} from "vue-icons-plus/tb";
import {useDebounceFn} from "@vueuse/core";
import {useReportStore} from "../../../Stores/report.js";

const props = defineProps({
    patient: {
        type: Object,
        default: null,
    },
    sourceStatus: {
        type: String,
        default: null,
    },
})

const show = defineModel('show', {type: Boolean, default: false})
const reportStore = useReportStore()
const formRef = ref(null)
const loading = ref(false)
const submitting = ref(false)
const operations = ref([])
const serviceLoading = ref(false)
const serviceOptions = ref([])
const editingOperationId = ref(null)

const form = reactive({
    service_id: null,
    service_code: '',
    service_name: '',
    urgency: 'plan',
    period: null,
})

const rules = {
    service_id: {
        required: true,
        message: 'Укажите услугу',
        trigger: ['change'],
        validator: (_rule, value) => {
            if (value === null || value === undefined || value === '') return false
            const id = Number(value)
            return Number.isInteger(id) && id > 0
        },
    },
    urgency: {
        required: true,
        message: 'Укажите срочность операции',
        trigger: ['change'],
    },
    period: {
        required: true,
        type: 'array',
        message: 'Укажите дату и время начала/окончания',
        trigger: ['change'],
        validator: (_rule, value) => {
            if (!Array.isArray(value) || value.length !== 2) return false
            if (!value[0] || !value[1]) return false
            return value[1] >= value[0]
        },
    },
}

const resetForm = () => {
    editingOperationId.value = null
    form.service_id = null
    form.service_code = ''
    form.service_name = ''
    form.urgency = 'plan'
    form.period = null
    serviceOptions.value = []
}

const urgencyOptions = [
    { label: 'Плановая', value: 'plan' },
    { label: 'Экстренная', value: 'emergency' },
]

const pad = (value) => String(value).padStart(2, '0')
const formatLocalDateTime = (timestamp) => {
    const date = new Date(timestamp)
    return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
}

const loadOperations = async () => {
    if (!props.patient?.department_patient_id) {
        operations.value = []
        return
    }

    loading.value = true
    try {
        operations.value = await reportStore.getManualPatientOperations(props.patient.department_patient_id)
    } finally {
        loading.value = false
    }
}

const loadServiceOptions = useDebounceFn(async (query) => {
    if (!query || query.trim().length < 2) {
        serviceOptions.value = []
        return
    }

    serviceLoading.value = true
    try {
        const items = await reportStore.searchMedicalServices(query.trim())
        serviceOptions.value = (items ?? []).map((item) => ({
            label: item.label,
            value: item.id,
            code: item.code,
            name: item.name,
        }))
    } finally {
        serviceLoading.value = false
    }
}, 300)

const handleServiceSearch = async (query) => {
    await loadServiceOptions(query)
}

const handleServiceChange = (value, option) => {
    const normalizedId = value === null || value === undefined || value === '' ? null : Number(value)
    form.service_id = Number.isInteger(normalizedId) && normalizedId > 0 ? normalizedId : null

    if (!option && form.service_id === null) {
        form.service_id = null
        form.service_code = ''
        form.service_name = ''
        return
    }

    if (!option || Array.isArray(option)) {
        return
    }

    form.service_code = option.code ?? ''
    form.service_name = option.name ?? ''
}

const toPeriod = (operation) => {
    if (!operation?.startAt || !operation?.endAt) return null
    return [new Date(operation.startAt).getTime(), new Date(operation.endAt).getTime()]
}

const startEdit = (operation) => {
    editingOperationId.value = operation.id
    form.period = toPeriod(operation)
    form.service_id = operation.service?.id ? Number(operation.service.id) : null
    form.service_code = operation.service?.code ?? ''
    form.service_name = operation.service?.name ?? ''
    form.urgency = operation.urgency ?? 'plan'

    if (operation.service?.label) {
        serviceOptions.value = [{
            label: operation.service.label,
            value: operation.service.id,
            code: operation.service.code,
            name: operation.service.name,
        }]
    }
}

const submit = async () => {
    if (!props.patient?.department_patient_id || submitting.value) return

    try {
        await formRef.value?.validate()
    } catch {
        return
    }

    submitting.value = true

    try {
        const payload = {
            service_id: Number(form.service_id),
            urgency: form.urgency,
            started_at: formatLocalDateTime(form.period[0]),
            ended_at: formatLocalDateTime(form.period[1]),
        }

        if (editingOperationId.value) {
            await reportStore.updateManualPatientOperation(
                props.patient.department_patient_id,
                editingOperationId.value,
                payload
            )
            window.$message.success('Операция обновлена')
        } else {
            await reportStore.createManualPatientOperation(props.patient.department_patient_id, payload)
            window.$message.success('Операция добавлена')
        }

        await reportStore.reloadReportPage()

        await Promise.all([
            loadOperations(),
            props.sourceStatus
                ? reportStore.loadPatientsByStatus(props.sourceStatus, { resetPage: true })
                : Promise.resolve(),
        ])

        resetForm()
    } finally {
        submitting.value = false
    }
}

const remove = async (operation) => {
    if (!props.patient?.department_patient_id) return

    await reportStore.deleteManualPatientOperation(props.patient.department_patient_id, operation.id)
    window.$message.success('Операция удалена')

    await reportStore.reloadReportPage()

    await Promise.all([
        loadOperations(),
        props.sourceStatus
            ? reportStore.loadPatientsByStatus(props.sourceStatus, { resetPage: true })
            : Promise.resolve(),
    ])

    if (editingOperationId.value === operation.id) {
        resetForm()
    }
}

const columns = computed(() => ([
    {
        title: 'Услуга',
        key: 'service',
        width: 320,
        render: (row) => h(
            NEllipsis,
            {
                tooltip: true,
            },
            {
                default: () => row.service?.label || 'Без услуги',
            }
        ),
    },
    {
        title: 'Срочность',
        key: 'urgency',
        width: 110,
        render: (row) => row.urgency === 'emergency' ? 'Э' : 'П',
    },
    {
        title: 'Начало',
        key: 'startAt',
        width: 165,
        render: (row) => row.startAt ? new Date(row.startAt).toLocaleString('ru-RU') : '-',
    },
    {
        title: 'Окончание',
        key: 'endAt',
        width: 165,
        render: (row) => row.endAt ? new Date(row.endAt).toLocaleString('ru-RU') : '-',
    },
    {
        title: 'Мин.',
        key: 'duration',
        width: 80,
        render: (row) => {
            const duration = Number(row.duration)
            return Number.isFinite(duration) ? Math.round(duration) : '-'
        },
    },
    {
        title: '',
        key: 'actions',
        width: 92,
        render: (row) => h(
            'div',
            { style: { display: 'flex', gap: '8px', justifyContent: 'center' } },
            [
                h(
                    NButton,
                    {
                        quaternary: true,
                        size: 'small',
                        onClick: () => startEdit(row),
                    },
                    {
                        icon: () => h(NIcon, {}, { default: () => h(TbPencil) }),
                    }
                ),
                h(
                    NPopconfirm,
                    {
                        onPositiveClick: () => remove(row),
                    },
                    {
                        trigger: () => h(
                            NButton,
                            { quaternary: true, type: 'error', size: 'small' },
                            { icon: () => h(NIcon, {}, { default: () => h(TbTrash) }) }
                        ),
                        default: () => 'Удалить операцию?',
                    }
                )
            ]
        )
    }
]))

watch(() => show.value, async (opened) => {
    if (!opened) {
        resetForm()
        return
    }

    await loadOperations()
}, {immediate: false})

watch(() => props.patient?.department_patient_id, async () => {
    if (show.value) {
        resetForm()
        await loadOperations()
    }
})
</script>

<template>
    <NModal
        v-model:show="show"
        preset="card"
        title="Операции спецконтингента"
        class="max-w-5xl"
        :mask-closable="false"
    >
        <NText class="mb-3 block">
            {{ patient?.fullname }}
        </NText>

        <NForm ref="formRef" :model="form" :rules="rules" label-placement="top" class="mb-4">
            <div class="grid grid-cols-1 md:grid-cols-3 gap-3">
                <NFormItem label="Услуга" path="service_id" class="mb-0">
                    <NSelect
                        v-model:value="form.service_id"
                        filterable
                        clearable
                        remote
                        :options="serviceOptions"
                        :loading="serviceLoading"
                        placeholder="Начните ввод кода или названия услуги"
                        @search="handleServiceSearch"
                        @update:value="handleServiceChange"
                    />
                </NFormItem>
                <NFormItem label="Срочность" path="urgency" class="mb-0">
                    <NSelect
                        v-model:value="form.urgency"
                        :options="urgencyOptions"
                    />
                </NFormItem>
                <NFormItem label="Начало и окончание" path="period" class="mb-0 md:col-span-1">
                    <NDatePicker
                        v-model:value="form.period"
                        type="datetimerange"
                        class="w-full"
                        clearable
                    />
                </NFormItem>
            </div>

            <div class="mt-3 flex items-center gap-2 justify-end">
                <NButton v-if="editingOperationId" @click="resetForm">Отмена редактирования</NButton>
                <NButton type="primary" :loading="submitting" @click="submit">
                    {{ editingOperationId ? 'Сохранить изменения' : 'Добавить операцию' }}
                </NButton>
            </div>
        </NForm>

        <NSpin :show="loading">
            <NDataTable
                :columns="columns"
                :data="operations"
                size="small"
                max-height="320"
                :row-key="(row) => row.id"
                class="text-sm!"
            />
        </NSpin>
    </NModal>
</template>

<style scoped>
:deep(.n-data-table-th),
:deep(.n-data-table-td) {
    font-size: var(--n-font-size);
}
</style>
