<script setup>
import { ref, reactive, computed, onMounted, watch } from 'vue'
import { router, Link } from '@inertiajs/vue3'
import axios from 'axios'
import {
    NButton, NText, NIcon, NSelect, NFlex, NSpin, NDropdown, useMessage, NEl
} from 'naive-ui'
import {
    TbArrowLeft, TbPencil, TbSettings, TbDeviceFloppy, TbDownload,
    TbChevronUp, TbChevronDown, TbBuildingHospital, TbReportMedical,
} from 'vue-icons-plus/tb'
import AppLayout from '../../Layouts/AppLayout.vue'
import AppContainer from '../../Components/AppContainer.vue'
import SectionCard from '../../Components/SectionCard.vue'
import DatePickerQuery from '../../Components/DatePickerQuery.vue'
import SettingsPanel from './Components/SettingsPanel.vue'
import ResultTable from './Components/ResultTable.vue'
import ReportChart from './Components/ReportChart.vue'
import EditReportModal from './Components/EditReportModal.vue'
import CustomMeasureModal from './Components/CustomMeasureModal.vue'

const props = defineProps({
    document: { type: Object, default: null },
    name: { type: String, default: 'Новый отчёт' },
    description: { type: String, default: '' },
    config: { type: Object, default: () => ({}) },
    datasets: { type: Array, default: () => [] },
    presets: { type: Array, default: () => [] },
    categories: { type: Array, default: () => [] },
    departments: { type: Array, default: () => [] },
    selectedDepartmentId: { type: [Number, String], default: null },
    isHeadOrAdmin: { type: Boolean, default: false },
    canManage: { type: Boolean, default: false },
    date: { type: Array, default: () => [] },
})

const message = useMessage()

const reportName = ref(props.name)
const reportDescription = ref(props.description)

const config = reactive({
    dataset: props.config.dataset ?? null,
    dimensions: props.config.dimensions ?? [],
    measures: props.config.measures ?? [],
    filters: props.config.filters ?? [],
    mode: props.config.mode ?? 'period',
    detalization: props.config.detalization ?? 'month',
    chart: { metric: props.config.chart?.metric ?? null, type: props.config.chart?.type ?? 'bar' },
})

const result = ref(null)
const loading = ref(false)
const showSettings = ref(true)
const showEdit = ref(false)
const showMeasureModal = ref(false)
const chartCollapsed = ref(false)

const departmentModel = ref(props.selectedDepartmentId)
const dateModel = ref(props.date?.length ? [...props.date] : null)

const currentDataset = computed(() => props.datasets.find((d) => d.key === config.dataset) ?? null)
const departmentOptions = computed(() => props.departments.map((d) => ({ label: d.name, value: d.id })))
const isFixed = computed(() => !!currentDataset.value?.fixed)
const canGenerate = computed(() => !!config.dataset && (isFixed.value || config.measures.length > 0))

const metricOptions = computed(() => {
    const ds = currentDataset.value
    if (ds && config.measures.length) {
        return config.measures
            .map((key) => ds.measures.find((m) => m.key === key))
            .filter(Boolean)
            .map((m) => ({ label: m.label, value: m.key }))
    }
    // Фиксированный отчёт: показатели для графика берём из колонок результата
    return (result.value?.columns ?? [])
        .filter((c) => c.kind === 'measure')
        .map((c) => ({ label: c.label, value: c.key }))
})

const baseMeasureOptions = computed(() => (currentDataset.value?.measures ?? []).map((m) => ({ label: m.label, value: m.key })))

const ensureChartMetric = () => {
    if (config.chart.metric === '__all') return // спец-режим «сравнение показателей»
    if (!config.chart.metric || !config.measures.includes(config.chart.metric)) {
        config.chart.metric = config.measures[0] ?? null
    }
}

const payload = () => ({
    dataset: config.dataset,
    dimensions: config.dimensions,
    measures: config.measures,
    filters: config.filters,
    mode: config.mode,
    detalization: config.detalization,
    chart: config.chart,
    name: reportName.value,
    departmentId: departmentModel.value,
    startAt: dateModel.value?.[0],
    endAt: dateModel.value?.[1],
})

const generate = async () => {
    if (!canGenerate.value) {
        message.warning('Выберите источник и хотя бы один показатель')
        return
    }
    ensureChartMetric()
    loading.value = true
    try {
        const { data } = await axios.post('/reports/run', payload())
        result.value = data
    } catch (e) {
        message.error('Не удалось сформировать отчёт')
    } finally {
        loading.value = false
    }
}

const onChangeDataset = (key) => {
    config.dataset = key
    config.dimensions = []
    config.measures = []
    config.filters = []
    config.chart = { metric: null, type: 'bar' }
    result.value = null
}

const onApplyPreset = (preset) => {
    const c = preset.config
    config.dataset = c.dataset
    config.dimensions = [...(c.dimensions ?? [])]
    config.measures = [...(c.measures ?? [])]
    config.filters = [...(c.filters ?? [])]
    config.mode = c.mode ?? 'period'
    config.detalization = c.detalization ?? 'month'
    config.chart = { metric: c.chart?.metric ?? null, type: c.chart?.type ?? 'bar' }
    if (preset.key !== 'blank' && reportName.value === 'Новый отчёт') reportName.value = preset.label
    result.value = null
}

const onChartUpdate = (chart) => {
    const metricChanged = chart.metric !== config.chart.metric
    config.chart = chart
    if (config.mode === 'dynamics' && metricChanged && result.value) generate()
}

const saveEdit = ({ name, description }) => {
    reportName.value = name
    reportDescription.value = description
}

const save = () => {
    const body = {
        name: reportName.value,
        description: reportDescription.value,
        dataset: config.dataset,
        config: {
            dimensions: config.dimensions,
            measures: config.measures,
            filters: config.filters,
            mode: config.mode,
            detalization: config.detalization,
            chart: config.chart,
        },
        period: dateModel.value ? { start: dateModel.value[0], end: dateModel.value[1] } : null,
    }
    if (props.document?.id) {
        router.put(`/reports/${props.document.id}`, body, { onSuccess: () => message.success('Отчёт сохранён') })
    } else {
        router.post('/reports', body)
    }
}

const download = async (kind) => {
    try {
        const { data } = await axios.post(`/reports/export/${kind}`, payload(), { responseType: 'blob' })
        const url = window.URL.createObjectURL(new Blob([data]))
        const a = document.createElement('a')
        a.href = url
        a.download = `${reportName.value || 'report'}.${kind === 'excel' ? 'xlsx' : 'pdf'}`
        document.body.appendChild(a)
        a.click()
        a.remove()
        window.URL.revokeObjectURL(url)
    } catch (e) {
        message.error('Не удалось выгрузить файл')
    }
}

const exportMenu = [
    { key: 'excel', label: 'Excel (.xlsx)' },
    { key: 'pdf', label: 'PDF' },
]

onMounted(() => {
    if (canGenerate.value) generate()
})

watch(() => config.dataset, ensureChartMetric)

// Смена периода/отделения — сразу пересобираем уже сформированный отчёт.
watch([dateModel, departmentModel], () => {
    if (result.value) generate()
})
</script>

<template>
    <AppLayout>
        <AppContainer>
            <div class="builder">
                <div class="builder-main">
                    <NButton text size="small" :tag="Link" href="/reports" style="margin-bottom: 8px;">
                        <template #icon><TbArrowLeft /></template>
                        Назад
                    </NButton>

                    <div class="builder-header">
                        <div>
                            <div class="title-row">
                                <h1 class="report-title text-nowrap">{{ reportName }}</h1>
                                <NButton v-if="canManage" text @click="showEdit = true"><NIcon :size="16"><TbPencil /></NIcon></NButton>
                            </div>
                            <NText v-if="reportDescription" depth="3" style="font-size: 13px;">{{ reportDescription }}</NText>
                        </div>
                        <NFlex :size="8" align="center">
                            <NButton type="primary" :loading="loading" @click="generate">Сформировать отчёт</NButton>
                            <NDropdown trigger="click" :options="exportMenu" @select="download">
                                <NButton>
                                    <template #icon><TbDownload /></template>
                                    Скачать
                                </NButton>
                            </NDropdown>
                            <NButton v-if="canManage" @click="save">
                                <template #icon><TbDeviceFloppy /></template>
                                Сохранить
                            </NButton>
                            <NButton :type="showSettings ? 'primary' : 'default'" ghost @click="showSettings = !showSettings">
                                <template #icon><TbSettings /></template>
                                Настройки
                            </NButton>
                        </NFlex>
                    </div>

                    <NFlex align="center" :size="12" :wrap="true" class="builder-toolbar">
                        <NSelect
                            v-if="departmentOptions.length > 1"
                            v-model:value="departmentModel"
                            :options="departmentOptions"
                            style="width: 240px;"
                        >
                            <template #prefix><TbBuildingHospital /></template>
                        </NSelect>
                        <DatePickerQuery
                            v-model:date="dateModel"
                            :is-head-or-admin="true"
                            local
                            hint
                        />
                    </NFlex>

                    <NSpin :show="loading">
                        <SectionCard no-padding title="Визуализация" style="margin-bottom: 16px;">
                            <div class="chart-block">
                                <ReportChart
                                    v-show="!chartCollapsed"
                                    :columns="result?.columns ?? []"
                                    :rows="result?.rows ?? []"
                                    :chart="config.chart"
                                    :mode="config.mode"
                                    :metric-options="metricOptions"
                                    @update:chart="onChartUpdate"
                                />
                                <div class="collapse-toggle" @click="chartCollapsed = !chartCollapsed">
                                    <NIcon><component :is="chartCollapsed ? TbChevronDown : TbChevronUp" /></NIcon>
                                </div>
                            </div>
                        </SectionCard>

                        <SectionCard title="Данные" no-padding>
                            <ResultTable :columns="result?.columns ?? []" :rows="result?.rows ?? []" />
                        </SectionCard>
                    </NSpin>
                </div>

                <transition name="slide">
                    <NEl v-if="showSettings" class="builder-side">
                        <SettingsPanel
                            :config="config"
                            :datasets="datasets"
                            :presets="presets"
                            :categories="categories"
                            :can-manage="canManage"
                            @close="showSettings = false"
                            @change-dataset="onChangeDataset"
                            @apply-preset="onApplyPreset"
                            @create-measure="showMeasureModal = true"
                        />
                    </NEl>
                </transition>
            </div>

            <EditReportModal
                v-model:show="showEdit"
                :name="reportName"
                :description="reportDescription"
                @save="saveEdit"
            />
            <CustomMeasureModal
                v-model:show="showMeasureModal"
                :dataset="config.dataset"
                :base-measures="baseMeasureOptions"
            />
        </AppContainer>
    </AppLayout>
</template>

<style scoped>
:deep(.n-data-table-th) { background: transparent !important; }
:deep(.n-data-table) { background: transparent; }
:deep(.n-data-table-wrapper) { border-radius: 0; }
:deep(.n-data-table-th .n-data-table-th__title) { font-size: 12px; }
:deep(.n-data-table-td) { font-size: 13px; }

.builder { display: flex; gap: 16px; align-items: flex-start; }
.builder-main { flex: 1; min-width: 0; }
.builder-side {
    width: 360px;
    flex-shrink: 0;
    position: sticky;
    top: 12px;
    border: 1px solid var(--n-border-color, rgba(255,255,255,.1));
    border-radius: 14px;
    background: var(--card-color);
    padding: 14px;
}
.builder-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 12px;
}
.title-row { display: flex; align-items: center; gap: 6px; }
.report-title { font-size: 22px; font-weight: 700; margin: 0; }
.builder-toolbar { margin-bottom: 16px; }
.chart-block { position: relative; padding: 16px; }
.collapse-toggle {
    position: absolute;
    left: 50%;
    bottom: -12px;
    transform: translateX(-50%);
    width: 28px;
    height: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--n-border-color, rgba(255,255,255,.12));
    border-radius: 8px;
    background: var(--n-card-color);
    cursor: pointer;
}
.slide-enter-active, .slide-leave-active { transition: opacity .15s, transform .15s; }
.slide-enter-from, .slide-leave-to { opacity: 0; transform: translateX(12px); }
@media (max-width: 1100px) {
    .builder { flex-direction: column; }
    .builder-side { width: 100%; position: static; }
}
</style>
