<script setup>
import { computed } from 'vue'
import { NSelect, NEmpty, useThemeVars } from 'naive-ui'
import VueApexCharts from 'vue3-apexcharts'

const props = defineProps({
    columns: { type: Array, default: () => [] },
    rows: { type: Array, default: () => [] },
    chart: { type: Object, default: () => ({ metric: null, type: 'bar' }) },
    mode: { type: String, default: 'period' },
    metricOptions: { type: Array, default: () => [] }, // [{ label, value }]
})

const emit = defineEmits(['update:chart'])

const themeVars = useThemeVars()

// --- Стили графиков, перенесённые со страницы «Статистика» (Headquarters) ---
const FONT = "'v-sans', ui-sans-serif, system-ui, sans-serif"
const cAxis = computed(() => themeVars.value.textColor3)
const cGrid = computed(() => themeVars.value.dividerColor)

// soften(color) = цвет темы, разбавленный фоном карточки (ApexCharts не понимает color-mix)
const SOFT_AMOUNT = 0.35
function parseColor(c) {
    if (!c) return { r: 0, g: 0, b: 0 }
    c = c.trim()
    if (c[0] === '#') {
        let h = c.slice(1)
        if (h.length === 3) h = h.split('').map((x) => x + x).join('')
        const n = parseInt(h, 16)
        return { r: (n >> 16) & 255, g: (n >> 8) & 255, b: n & 255 }
    }
    const m = c.match(/rgba?\(([^)]+)\)/i)
    if (m) {
        const [r, g, b] = m[1].split(',').map((s) => parseFloat(s))
        return { r, g, b }
    }
    return { r: 0, g: 0, b: 0 }
}
function toHex({ r, g, b }) {
    const h = (v) => Math.round(Math.max(0, Math.min(255, v))).toString(16).padStart(2, '0')
    return `#${h(r)}${h(g)}${h(b)}`
}
function soften(color, amount = SOFT_AMOUNT) {
    const a = parseColor(color)
    const b = parseColor(themeVars.value.cardColor)
    return toHex({
        r: a.r * (1 - amount) + b.r * amount,
        g: a.g * (1 - amount) + b.g * amount,
        b: a.b * (1 - amount) + b.b * amount,
    })
}

// Семантические цвета + различимая палитра (без двух зелёных, как было раньше).
// Приглушённая палитра (для заливок: столбцы/донат) и яркая (для тонких линий).
const buildColors = (vivid) => {
    const f = vivid ? (c) => c : (c) => soften(c)
    return {
        green: f(themeVars.value.successColor),
        red: f(themeVars.value.errorColor),
        gray: f(themeVars.value.textColor3),
        blue: f(themeVars.value.infoColor),
        orange: f(themeVars.value.warningColor),
        purple: f('#8a63d2'),
        teal: f('#13c2c2'),
        pink: f('#eb6ea5'),
    }
}
const SOFT = computed(() => buildColors(false))
const VIVID = computed(() => buildColors(true))

const fallbackPalette = (c) => [c.green, c.blue, c.orange, c.purple, c.teal, c.pink, c.gray, c.red]

// Цвет категории: экстренное/смерть → красный, плановое → серый, иначе — различимый из палитры.
function colorFor(label, index, vivid = false) {
    const c = vivid ? VIVID.value : SOFT.value
    const t = String(label ?? '').toLowerCase()
    if (/экстрен|неотлож|emergency/.test(t)) return c.red
    if (/умер|смерт|летал|decease|death/.test(t)) return c.red
    if (/планов|plan/.test(t)) return c.gray
    const p = fallbackPalette(c)
    return p[index % p.length]
}

const baseChart = (type) => ({
    type,
    background: 'transparent',
    toolbar: { show: false },
    fontFamily: FONT,
    animations: { enabled: true, speed: 600, dynamicAnimation: { enabled: true, speed: 400 } },
})
const baseTooltip = computed(() => ({ theme: 'dark', style: { fontSize: '12px', fontFamily: FONT } }))
const baseGrid = computed(() => ({ borderColor: cGrid.value, strokeDashArray: 4, xaxis: { lines: { show: false } } }))

const typeOptions = [
    { label: 'Столбцы', value: 'bar' },
    { label: 'Линия', value: 'line' },
    { label: 'Круговая', value: 'donut' },
]

const dimensionCols = computed(() => props.columns.filter((c) => c.kind === 'dimension'))
const periodCols = computed(() => props.columns.filter((c) => c.kind === 'period'))

const metric = computed(() => props.chart.metric ?? props.metricOptions[0]?.value ?? null)
const metricLabel = computed(() => props.metricOptions.find((m) => m.value === metric.value)?.label ?? 'Показатель')

// Режим «сравнение показателей»: слайсы/столбцы = сами показатели (Поступило/Выписано/…),
// а не категории измерения. Доступен, когда выбрано ≥2 показателей и это не динамика.
const ALL_METRICS = '__all'
const isAllMetrics = computed(() => metric.value === ALL_METRICS && props.mode !== 'dynamics')
const metricSelectOptions = computed(() => {
    const opts = props.metricOptions.map((m) => ({ label: m.label, value: m.value }))
    if (opts.length > 1) opts.unshift({ label: 'Все показатели (сравнение)', value: ALL_METRICS })
    return opts
})

const setMetric = (value) => emit('update:chart', { ...props.chart, metric: value })
const setType = (value) => emit('update:chart', { ...props.chart, type: value })

const num = (v) => {
    const n = Number(v)
    return Number.isNaN(n) ? 0 : n
}

const apexType = computed(() => {
    if (props.chart.type === 'donut') return props.mode === 'dynamics' ? 'line' : 'donut'
    return props.chart.type === 'line' ? 'line' : 'bar'
})

const categories = computed(() => {
    if (props.mode === 'dynamics') return periodCols.value.map((c) => c.label)
    if (isAllMetrics.value) return props.metricOptions.map((m) => m.label)
    const dim = dimensionCols.value[0]
    return dim ? props.rows.map((r) => r[dim.key]) : props.rows.map((_, i) => `#${i + 1}`)
})

const series = computed(() => {
    if (props.mode === 'dynamics') {
        const labelKey = dimensionCols.value[0]?.key ?? '__metric'
        return props.rows.map((r) => ({
            name: r[labelKey] ?? metricLabel.value,
            data: periodCols.value.map((c) => num(r[c.key])),
        }))
    }

    // Сравнение показателей: каждое значение = сумма показателя по всем строкам.
    if (isAllMetrics.value) {
        const sums = props.metricOptions.map((m) => props.rows.reduce((s, r) => s + num(r[m.value]), 0))
        return apexType.value === 'donut' ? sums : [{ name: 'Показатели', data: sums }]
    }

    const data = props.rows.map((r) => num(r[metric.value]))
    return apexType.value === 'donut' ? data : [{ name: metricLabel.value, data }]
})

// Раскрашивать каждый столбец отдельно, когда это одна серия по нескольким категориям
// (напр. срочность/исход/показатели) и категорий немного.
const distributedBar = computed(() =>
    props.mode !== 'dynamics' && apexType.value === 'bar' && (isAllMetrics.value || categories.value.length <= 12),
)

const isLine = computed(() => apexType.value === 'line')

const chartColors = computed(() => {
    // Линии берут яркие цвета, заливки (столбцы/донат) — приглушённые.
    if (props.mode === 'dynamics') {
        return series.value.map((s, i) => colorFor(s.name, i, isLine.value))
    }
    // Круговая и «распределённый» столбчатый: цвет на категорию.
    if (apexType.value === 'donut' || distributedBar.value) {
        return categories.value.map((c, i) => colorFor(c, i, false))
    }
    // Одна серия линией/столбцами без распределения — один цвет.
    return [colorFor(metricLabel.value, 0, isLine.value)]
})

const options = computed(() => {
    const base = {
        chart: baseChart(apexType.value),
        colors: chartColors.value,
        dataLabels: { enabled: false },
        tooltip: baseTooltip.value,
        legend: { position: 'bottom', labels: { colors: cAxis.value }, fontSize: '12px', fontFamily: FONT, markers: { size: 6, shape: 'circle' } },
        noData: { text: 'Нет данных', style: { fontFamily: FONT } },
    }

    if (apexType.value === 'donut') {
        return {
            ...base,
            labels: categories.value,
            stroke: { width: 0 },
            legend: { ...base.legend, position: 'right' },
            plotOptions: { pie: { donut: { size: '62%' } } },
        }
    }

    return {
        ...base,
        grid: baseGrid.value,
        plotOptions: { bar: { borderRadius: 5, borderRadiusApplication: 'end', columnWidth: '60%', distributed: distributedBar.value } },
        legend: { ...base.legend, show: props.mode === 'dynamics' },
        stroke: isLine.value
            ? { width: 4, curve: 'smooth', lineCap: 'round' }
            : { width: 0 },
        markers: isLine.value
            ? { size: 5, strokeWidth: 0, hover: { sizeOffset: 2 } }
            : { size: 0 },
        fill: { type: 'solid', opacity: 1 },
        xaxis: {
            categories: categories.value,
            labels: {
                style: { colors: cAxis.value, fontSize: '11px', fontFamily: FONT },
                rotate: -40,
                rotateAlways: categories.value.length > 6,
                hideOverlappingLabels: true,
                trim: true,
            },
            axisBorder: { show: false },
            axisTicks: { show: false },
        },
        yaxis: { labels: { style: { colors: cAxis.value, fontFamily: FONT } }, tickAmount: 4 },
    }
})

const hasData = computed(() => props.rows.length > 0 && series.value.length > 0)
</script>

<template>
    <div class="chart-wrap">
        <div class="chart-toolbar">
            <NSelect
                v-if="metricOptions.length"
                :value="metric"
                :options="metricSelectOptions"
                size="small"
                style="width: 240px;"
                :disabled="mode === 'dynamics' && metricOptions.length <= 1"
                @update:value="setMetric"
            />
            <NSelect
                :value="chart.type"
                :options="typeOptions"
                size="small"
                style="width: 140px;"
                @update:value="setType"
            />
        </div>

        <NEmpty v-if="!hasData" description="Диаграмма появится после формирования отчёта" style="padding: 32px;" />
        <VueApexCharts
            v-else
            :key="apexType + '|' + mode"
            :type="apexType"
            height="280"
            :options="options"
            :series="series"
        />
    </div>
</template>

<style scoped>
.chart-wrap { position: relative; }
.chart-toolbar {
    display: flex;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 8px;
}
</style>
