<template>
    <div class="daily-matrix" v-loading="loading">
        <div class="daily-matrix__toolbar">
            <div class="daily-matrix__toolbar-left">
                <el-radio-group v-model="rangeMode" @change="handleRangeModeChange">
                    <el-radio-button value="7">最近7天</el-radio-button>
                    <el-radio-button value="30">最近30天</el-radio-button>
                    <el-radio-button value="custom">自定义</el-radio-button>
                </el-radio-group>

                <el-date-picker
                    v-if="rangeMode === 'custom'"
                    v-model="customRange"
                    type="daterange"
                    value-format="YYYY-MM-DD"
                    range-separator="至"
                    start-placeholder="开始日期"
                    end-placeholder="结束日期"
                    :clearable="false"
                    :disabled-date="disabledFutureDate"
                    @change="handleCustomRangeChange"
                />
            </div>

            <div v-if="canEditDailyRecord" class="daily-matrix__toolbar-right">
                <el-button type="primary" @click="openQuickAdd('blood')">+血糖</el-button>
                <el-button @click="openQuickAdd('diet')">+饮食</el-button>
                <el-button @click="openQuickAdd('exercise')">+运动</el-button>
                <el-button @click="openQuickAdd('tracking')">+备注</el-button>
                <el-button @click="fetchTracking">刷新</el-button>
            </div>
            <div v-else class="daily-matrix__toolbar-right">
                <el-button @click="fetchTracking">刷新</el-button>
            </div>
        </div>

        <div ref="tableWrapRef" class="daily-matrix__table-wrap">
        <el-table
            :data="matrixRows"
            border
            stripe
            row-key="key"
            class="daily-matrix__table"
            empty-text="暂无记录"
        >
            <el-table-column prop="label" label="指标" fixed="left" width="120" />
            <el-table-column
                v-for="date in visibleDates"
                :key="date"
                :label="formatColumnDate(date)"
                :min-width="dateColumnMinWidth"
                align="center"
            >
                <template #default="{ row }">
                    <div
                        class="daily-matrix__cell"
                        :class="{
                            'is-clickable': isCellClickable(row.key, date),
                            'is-empty': !getCell(row.key, date).hasRecord,
                            'is-high': getCell(row.key, date).isHigh
                        }"
                        @click="handleCellClick(row.key, date)"
                    >
                        <template v-if="row.key === 'tracking' && getTrackingContent(date)">
                            <el-tooltip placement="top" effect="light" :show-after="150">
                                <template #content>
                                    <div class="daily-matrix__tracking-tooltip">
                                        <div
                                            v-for="(line, index) in splitTrackingLines(getTrackingContent(date))"
                                            :key="`${date}-${index}`"
                                            class="daily-matrix__tracking-tooltip-line"
                                        >
                                            {{ line }}
                                        </div>
                                    </div>
                                </template>
                                <div class="daily-matrix__tracking-preview">
                                    {{ getTrackingPreview(getTrackingContent(date)) }}
                                </div>
                            </el-tooltip>
                        </template>
                        <template v-else-if="getCell(row.key, date).value">
                            <span>{{ getCell(row.key, date).value }}</span>
                            <span v-if="getCell(row.key, date).isHigh" class="daily-matrix__cell-up">↑</span>
                        </template>
                        <template v-else>—</template>
                    </div>
                </template>
            </el-table-column>
        </el-table>
        </div>

        <div class="daily-matrix__chart">
            <div class="daily-matrix__section-title">血糖趋势</div>
            <v-charts
                v-if="bloodTrendHasData"
                class="daily-matrix__chart-canvas"
                :option="bloodTrendOption"
                autoresize
            />
            <el-empty v-else description="当前时间范围暂无血糖数据" :image-size="84" />
        </div>

        <div v-if="canViewTodoList" class="daily-matrix__todo">
            <div class="daily-matrix__section-title">待办事项</div>
            <DiagnosisTodoList
                :diagnosis-id="diagnosisId"
                :patient-id="patientId"
                :patient-name="patientName"
                :read-only="readOnly"
            />
        </div>

        <el-dialog v-model="bloodDialogVisible" :title="bloodDialogTitle" width="600px" :close-on-click-modal="false">
            <el-form :model="bloodForm" label-width="120px">
                <el-form-item label="记录日期" required>
                    <el-date-picker
                        v-model="bloodForm.record_date"
                        type="date"
                        placeholder="选择日期"
                        value-format="YYYY-MM-DD"
                        class="w-full"
                    />
                </el-form-item>
                <el-form-item label="记录时间">
                    <el-time-picker
                        v-model="bloodForm.record_time"
                        placeholder="选择时间"
                        format="HH:mm"
                        value-format="HH:mm"
                        class="w-full"
                    />
                </el-form-item>
                <el-form-item label="空腹血糖">
                    <el-input-number v-model="bloodForm.fasting_blood_sugar" :precision="2" :step="0.1" :min="0" :max="50" />
                    <span class="ml-2">mmol/L</span>
                </el-form-item>
                <el-form-item label="餐后2小时血糖">
                    <el-input-number v-model="bloodForm.postprandial_blood_sugar" :precision="2" :step="0.1" :min="0" :max="50" />
                    <span class="ml-2">mmol/L</span>
                </el-form-item>
                <el-form-item label="其他血糖">
                    <el-input v-model="bloodForm.other_blood_sugar" type="number" style="width: 200px" />
                    <span class="ml-2">mmol/L</span>
                </el-form-item>
                <el-form-item label="收缩压（高压）">
                    <el-input-number v-model="bloodForm.systolic_pressure" :min="0" :max="300" />
                    <span class="ml-2">mmHg</span>
                </el-form-item>
                <el-form-item label="舒张压（低压）">
                    <el-input-number v-model="bloodForm.diastolic_pressure" :min="0" :max="200" />
                    <span class="ml-2">mmHg</span>
                </el-form-item>
                <el-form-item label="西药">
                    <el-input v-model="bloodForm.western_medicine" />
                </el-form-item>
                <el-form-item label="胰岛素">
                    <el-input v-model="bloodForm.insulin" />
                </el-form-item>
                <el-form-item label="备注">
                    <el-input v-model="bloodForm.remark" type="textarea" :rows="3" />
                </el-form-item>
            </el-form>
            <template #footer>
                <el-button @click="bloodDialogVisible = false">取消</el-button>
                <el-button type="primary" :loading="bloodSubmitting" :disabled="!canEditDailyRecord" @click="submitBlood">确定</el-button>
            </template>
        </el-dialog>

        <el-dialog v-model="dietDialogVisible" :title="dietDialogTitle" width="800px" :close-on-click-modal="false">
            <el-form :model="dietForm" label-width="100px">
                <el-form-item label="记录日期" required>
                    <el-date-picker
                        v-model="dietForm.record_date"
                        type="date"
                        placeholder="选择日期"
                        value-format="YYYY-MM-DD"
                        class="w-full"
                    />
                </el-form-item>
                <el-divider content-position="left">早餐</el-divider>
                <el-form-item label="食物描述">
                    <el-input v-model="dietForm.breakfast_foods" type="textarea" :rows="2" placeholder="请输入早餐食物" />
                </el-form-item>
                <el-form-item label="图片">
                    <material-picker v-model="dietForm.breakfast_images" :limit="3" type="image" />
                </el-form-item>
                <el-divider content-position="left">午餐</el-divider>
                <el-form-item label="食物描述">
                    <el-input v-model="dietForm.lunch_foods" type="textarea" :rows="2" placeholder="请输入午餐食物" />
                </el-form-item>
                <el-form-item label="图片">
                    <material-picker v-model="dietForm.lunch_images" :limit="3" type="image" />
                </el-form-item>
                <el-divider content-position="left">晚餐</el-divider>
                <el-form-item label="食物描述">
                    <el-input v-model="dietForm.dinner_foods" type="textarea" :rows="2" placeholder="请输入晚餐食物" />
                </el-form-item>
                <el-form-item label="图片">
                    <material-picker v-model="dietForm.dinner_images" :limit="3" type="image" />
                </el-form-item>
                <el-form-item label="备注">
                    <el-input v-model="dietForm.note" type="textarea" :rows="3" placeholder="请输入备注" />
                </el-form-item>
            </el-form>
            <template #footer>
                <el-button @click="dietDialogVisible = false">取消</el-button>
                <el-button type="primary" :loading="dietSubmitting" :disabled="!canEditDailyRecord" @click="submitDiet">确定</el-button>
            </template>
        </el-dialog>

        <el-dialog v-model="exerciseDialogVisible" :title="exerciseDialogTitle" width="600px" :close-on-click-modal="false">
            <el-form :model="exerciseForm" label-width="120px">
                <el-form-item label="记录日期" required>
                    <el-date-picker
                        v-model="exerciseForm.record_date"
                        type="date"
                        placeholder="选择日期"
                        value-format="YYYY-MM-DD"
                        class="w-full"
                    />
                </el-form-item>
                <el-form-item label="运动类型" required>
                    <el-select v-model="exerciseForm.exercise_type" placeholder="请选择运动类型" class="w-full">
                        <el-option label="散步" value="散步" />
                        <el-option label="慢跑" value="慢跑" />
                        <el-option label="游泳" value="游泳" />
                        <el-option label="瑜伽" value="瑜伽" />
                        <el-option label="骑自行车" value="骑自行车" />
                        <el-option label="打太极拳" value="打太极拳" />
                        <el-option label="其他" value="其他" />
                    </el-select>
                </el-form-item>
                <el-form-item label="运动时长（分钟）" required>
                    <el-input-number v-model="exerciseForm.duration" :min="0" :max="300" />
                </el-form-item>
                <el-form-item label="运动强度" required>
                    <el-select v-model="exerciseForm.intensity" placeholder="请选择运动强度" class="w-full">
                        <el-option label="低强度" :value="1" />
                        <el-option label="中强度" :value="2" />
                        <el-option label="高强度" :value="3" />
                    </el-select>
                </el-form-item>
                <el-form-item label="运动图片">
                    <material-picker v-model="exerciseForm.images" :limit="3" type="image" />
                </el-form-item>
                <el-form-item label="备注">
                    <el-input v-model="exerciseForm.note" type="textarea" :rows="3" />
                </el-form-item>
            </el-form>
            <template #footer>
                <el-button @click="exerciseDialogVisible = false">取消</el-button>
                <el-button type="primary" :loading="exerciseSubmitting" :disabled="!canEditDailyRecord" @click="submitExercise">确定</el-button>
            </template>
        </el-dialog>

        <el-dialog v-model="trackingDialogVisible" :title="trackingDialogTitle" width="600px" :close-on-click-modal="false">
            <el-form :model="trackingForm" label-width="100px">
                <el-form-item label="记录日期" required>
                    <el-date-picker
                        v-model="trackingForm.note_date"
                        type="date"
                        placeholder="选择日期"
                        value-format="YYYY-MM-DD"
                        class="w-full"
                        :disabled="true"
                    />
                </el-form-item>
                <el-form-item v-if="trackingForm.existing_content" label="已有备注">
                    <div class="daily-matrix__tracking-existing">
                        <div
                            v-for="(line, index) in splitTrackingLines(trackingForm.existing_content)"
                            :key="`${trackingForm.note_date}-${index}`"
                            class="daily-matrix__tracking-line"
                        >
                            {{ line }}
                        </div>
                    </div>
                </el-form-item>
                <el-form-item :label="trackingCanSubmit ? '追加备注' : '备注内容'" required>
                    <el-input
                        v-model="trackingForm.content"
                        type="textarea"
                        :rows="5"
                        maxlength="1000"
                        show-word-limit
                        :disabled="!trackingCanSubmit"
                        :placeholder="trackingCanSubmit ? '请输入跟踪备注' : '历史跟踪备注仅支持查看'"
                    />
                </el-form-item>
            </el-form>
            <template #footer>
                <el-button @click="trackingDialogVisible = false">取消</el-button>
                <el-button v-if="trackingCanSubmit" type="primary" :loading="trackingSubmitting" @click="submitTracking">确定</el-button>
            </template>
        </el-dialog>
    </div>
</template>

<script setup lang="ts">
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
import vCharts from 'vue-echarts'
import DiagnosisTodoList from './DiagnosisTodoList.vue'
import { hasPermission } from '@/utils/perm'
import {
    bloodRecordAdd,
    bloodRecordEdit,
    diagnosisAddTrackingNote,
    diagnosisTrackingWindow,
    diagnosisTrackingNotes,
    dietRecordAdd,
    dietRecordEdit,
    exerciseRecordAdd,
    exerciseRecordEdit
} from '@/api/tcm'
import {
    formatBp,
    isHighBloodPressure,
    isHighFastingBloodSugar,
    isHighOtherBloodSugar,
    isHighPostprandialBloodSugar
} from '@/utils/blood-thresholds'
import feedback from '@/utils/feedback'

interface Props {
    diagnosisId: number
    patientId: number
    age?: number
    readOnly?: boolean
    patientName?: string
}

interface BloodRecord {
    id?: number | string
    diagnosis_id?: number
    patient_id?: number
    record_date?: string
    record_time?: string
    record_date_ts?: number
    fasting_blood_sugar?: any
    postprandial_blood_sugar?: any
    other_blood_sugar?: any
    systolic_pressure?: any
    diastolic_pressure?: any
    western_medicine?: string
    insulin?: string
    remark?: string
    [key: string]: any
}

interface DietRecord {
    id?: number | string
    diagnosis_id?: number
    patient_id?: number
    record_date?: string
    breakfast?: string
    breakfast_foods?: string
    breakfast_images?: string[]
    lunch?: string
    lunch_foods?: string
    lunch_images?: string[]
    dinner?: string
    dinner_foods?: string
    dinner_images?: string[]
    note?: string
    [key: string]: any
}

interface ExerciseRecord {
    id?: number | string
    diagnosis_id?: number
    patient_id?: number
    record_date?: string
    exercise_type?: string
    duration?: number
    intensity?: number
    intensity_text?: string
    images?: string[]
    note?: string
    [key: string]: any
}

interface TrackingNoteRecord {
    id?: number | string
    note_date?: string
    content?: string | null
}

type RangeMode = '7' | '30' | 'custom'
type DialogKind = 'blood' | 'diet' | 'exercise' | 'tracking'
const DAILY_RECORD_PERMS = ['tcm.diagnosis/dailyRecord']

const props = withDefaults(defineProps<Props>(), {
    age: undefined,
    readOnly: false,
    patientName: ''
})

const diagnosisId = computed(() => Number(props.diagnosisId || 0))
const patientId = computed(() => Number(props.patientId || 0))
const readOnly = computed(() => !!props.readOnly)
const patientName = computed(() => props.patientName || '')
const hasDailyRecordPermission = computed(() => hasPermission(DAILY_RECORD_PERMS))
const canEditDailyRecord = computed(() => hasDailyRecordPermission.value && !readOnly.value)
const canViewTodoList = computed(() => hasDailyRecordPermission.value)

const loading = ref(false)
const rangeMode = ref<RangeMode>('7')
const customRange = ref<[string, string] | null>(null)
const bloodRecords = ref<BloodRecord[]>([])
const dietRecords = ref<DietRecord[]>([])
const exerciseRecords = ref<ExerciseRecord[]>([])
const trackingNotes = ref<TrackingNoteRecord[]>([])

const bloodDialogVisible = ref(false)
const dietDialogVisible = ref(false)
const exerciseDialogVisible = ref(false)
const trackingDialogVisible = ref(false)
const bloodSubmitting = ref(false)
const dietSubmitting = ref(false)
const exerciseSubmitting = ref(false)
const trackingSubmitting = ref(false)

const bloodForm = ref<BloodRecord>(createBloodForm())
const dietForm = ref<DietRecord>(createDietForm())
const exerciseForm = ref<ExerciseRecord>(createExerciseForm())
const trackingForm = ref({
    note_date: '',
    existing_content: '',
    content: ''
})

const bloodDialogTitle = computed(() => (bloodForm.value.id ? '编辑血糖血压记录' : '新增血糖血压记录'))
const dietDialogTitle = computed(() => (dietForm.value.id ? '编辑饮食记录' : '新增饮食记录'))
const exerciseDialogTitle = computed(() => (exerciseForm.value.id ? '编辑运动记录' : '新增运动记录'))
const todayDate = computed(() => formatDate(new Date()))
const trackingCanSubmit = computed(() => !readOnly.value && trackingForm.value.note_date === todayDate.value)
const trackingDialogTitle = computed(() => (trackingCanSubmit.value ? '新增/追加跟踪备注' : '查看跟踪备注'))
const tableWrapRef = ref<HTMLElement | null>(null)
const tableWrapWidth = ref(0)

const metricRows = [
    { key: 'fasting', label: '空腹血糖' },
    { key: 'postprandial', label: '餐后2h血糖' },
    { key: 'other', label: '其他血糖' },
    { key: 'bp', label: '血压' },
    { key: 'western', label: '西药' },
    { key: 'insulin', label: '胰岛素' },
    { key: 'breakfast', label: '早餐' },
    { key: 'lunch', label: '午餐' },
    { key: 'dinner', label: '晚餐' },
    { key: 'exercise', label: '运动' },
    { key: 'tracking', label: '跟踪备注' }
] as const

const matrixRows = computed(() => [...metricRows])
const fixedLabelWidth = 120
const dateColumnMinWidth = computed(() => {
    const count = visibleDates.value.length
    if (count <= 0) return 100
    if (count > 7) return 100
    const usableWidth = Math.max(tableWrapWidth.value - fixedLabelWidth - 2, 0)
    const dynamicWidth = usableWidth > 0 ? Math.floor(usableWidth / count) : 100
    return Math.max(100, dynamicWidth)
})

let requestSeq = 0

function formatDate(date: Date): string {
    return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`
}

function parseDate(date: string): Date {
    return new Date(`${date}T00:00:00`)
}

function updateTableWrapWidth() {
    tableWrapWidth.value = tableWrapRef.value?.clientWidth || 0
}

function createBloodForm(date = ''): BloodRecord {
    return {
        id: '',
        diagnosis_id: diagnosisId.value,
        patient_id: patientId.value,
        record_date: date,
        record_time: '',
        fasting_blood_sugar: 0,
        postprandial_blood_sugar: 0,
        other_blood_sugar: '',
        systolic_pressure: 0,
        diastolic_pressure: 0,
        western_medicine: '',
        insulin: '',
        remark: ''
    }
}

function createDietForm(date = ''): DietRecord {
    return {
        id: '',
        diagnosis_id: diagnosisId.value,
        patient_id: patientId.value,
        record_date: date,
        breakfast_foods: '',
        breakfast_images: [],
        lunch_foods: '',
        lunch_images: [],
        dinner_foods: '',
        dinner_images: [],
        note: ''
    }
}

function createExerciseForm(date = ''): ExerciseRecord {
    return {
        id: '',
        diagnosis_id: diagnosisId.value,
        patient_id: patientId.value,
        record_date: date,
        exercise_type: '',
        duration: 0,
        intensity: 1,
        images: [],
        note: ''
    }
}

function disabledFutureDate(date: Date) {
    return date.getTime() > Date.now()
}

function computeRange(mode: RangeMode): { start: string; end: string } {
    if (mode === 'custom') {
        const [start, end] = customRange.value || ['', '']
        return { start: start || '', end: end || '' }
    }
    const days = mode === '7' ? 7 : 30
    const end = new Date()
    end.setHours(0, 0, 0, 0)
    const start = new Date(end)
    start.setDate(start.getDate() - (days - 1))
    return { start: formatDate(start), end: formatDate(end) }
}

const currentRange = computed(() => computeRange(rangeMode.value))

const visibleDates = computed(() => {
    const { start, end } = currentRange.value
    if (!start || !end) return []
    const dates: string[] = []
    const cursor = parseDate(end)
    const lower = parseDate(start).getTime()
    while (cursor.getTime() >= lower) {
        dates.push(formatDate(cursor))
        cursor.setDate(cursor.getDate() - 1)
    }
    return dates
})

const bloodByDate = computed(() => {
    const map = new Map<string, BloodRecord>()
    for (const record of bloodRecords.value) {
        const date = String(record.record_date || '')
        if (!date) continue
        if (!map.has(date)) {
            map.set(date, {
                id: record.id,
                diagnosis_id: record.diagnosis_id,
                patient_id: record.patient_id,
                record_date: date,
                record_time: record.record_time || '',
                record_date_ts: record.record_date_ts
            })
        }
        const merged = map.get(date)!
        const fields: Array<keyof BloodRecord> = [
            'fasting_blood_sugar',
            'postprandial_blood_sugar',
            'other_blood_sugar',
            'systolic_pressure',
            'diastolic_pressure',
            'western_medicine',
            'insulin',
            'remark'
        ]
        for (const field of fields) {
            if (
                (merged[field] === undefined || merged[field] === null || merged[field] === '') &&
                record[field] !== undefined &&
                record[field] !== null &&
                record[field] !== ''
            ) {
                ;(merged as any)[field] = record[field]
            }
        }
    }
    return map
})

const dietByDate = computed(() => {
    const map = new Map<string, DietRecord>()
    for (const record of dietRecords.value) {
        const date = String(record.record_date || '')
        if (!date || map.has(date)) continue
        map.set(date, record)
    }
    return map
})

const exerciseByDate = computed(() => {
    const map = new Map<string, ExerciseRecord>()
    for (const record of exerciseRecords.value) {
        const date = String(record.record_date || '')
        if (!date || map.has(date)) continue
        map.set(date, record)
    }
    return map
})

const trackingByDate = computed(() => {
    const map = new Map<string, TrackingNoteRecord>()
    for (const record of trackingNotes.value) {
        const date = String(record.note_date || '')
        if (!date || map.has(date)) continue
        map.set(date, record)
    }
    return map
})

const chartDates = computed(() => [...visibleDates.value].reverse())

const bloodTrendSeries = computed(() => {
    return chartDates.value.reduce(
        (acc, date) => {
            const blood = bloodByDate.value.get(date)
            acc.fasting.push(parseTrendNumber(blood?.fasting_blood_sugar))
            acc.postprandial.push(parseTrendNumber(blood?.postprandial_blood_sugar))
            return acc
        },
        {
            fasting: [] as Array<number | null>,
            postprandial: [] as Array<number | null>
        }
    )
})

const bloodTrendHasData = computed(() => {
    return [...bloodTrendSeries.value.fasting, ...bloodTrendSeries.value.postprandial].some((value) => value != null)
})

const bloodTrendOption = computed(() => ({
    tooltip: {
        trigger: 'axis'
    },
    legend: {
        top: 0,
        data: ['空腹血糖', '餐后血糖']
    },
    grid: {
        left: 24,
        right: 24,
        top: 52,
        bottom: 20,
        containLabel: true
    },
    xAxis: {
        type: 'category',
        boundaryGap: false,
        data: chartDates.value.map((date) => formatColumnDate(date))
    },
    yAxis: {
        type: 'value',
        name: 'mmol/L',
        splitLine: {
            lineStyle: {
                color: '#e5e7eb'
            }
        }
    },
    series: [
        {
            name: '空腹血糖',
            type: 'line',
            smooth: true,
            connectNulls: true,
            data: bloodTrendSeries.value.fasting,
            symbolSize: 7,
            itemStyle: {
                color: '#2563eb'
            },
            lineStyle: {
                width: 3,
                color: '#2563eb'
            }
        },
        {
            name: '餐后血糖',
            type: 'line',
            smooth: true,
            connectNulls: true,
            data: bloodTrendSeries.value.postprandial,
            symbolSize: 7,
            itemStyle: {
                color: '#f97316'
            },
            lineStyle: {
                width: 3,
                color: '#f97316'
            }
        }
    ]
}))

function formatColumnDate(date: string) {
    return date.slice(5)
}

function parseTrendNumber(value: unknown): number | null {
    if (value === '' || value == null) return null
    const parsed = Number(value)
    if (!Number.isFinite(parsed) || parsed === 0) return null
    return parsed
}

function getCell(metric: string, date: string): { value: string; isHigh: boolean; hasRecord: boolean } {
    const blood = bloodByDate.value.get(date)
    const diet = dietByDate.value.get(date)
    const exercise = exerciseByDate.value.get(date)
    const tracking = trackingByDate.value.get(date)
    switch (metric) {
        case 'fasting':
            return {
                value: blood?.fasting_blood_sugar != null && blood.fasting_blood_sugar !== '' ? String(blood.fasting_blood_sugar) : '',
                isHigh: isHighFastingBloodSugar(blood?.fasting_blood_sugar, props.age),
                hasRecord: !!blood && blood.fasting_blood_sugar != null && blood.fasting_blood_sugar !== ''
            }
        case 'postprandial':
            return {
                value: blood?.postprandial_blood_sugar != null && blood.postprandial_blood_sugar !== '' ? String(blood.postprandial_blood_sugar) : '',
                isHigh: isHighPostprandialBloodSugar(blood?.postprandial_blood_sugar, props.age),
                hasRecord: !!blood && blood.postprandial_blood_sugar != null && blood.postprandial_blood_sugar !== ''
            }
        case 'other':
            return {
                value: blood?.other_blood_sugar != null && blood.other_blood_sugar !== '' ? String(blood.other_blood_sugar) : '',
                isHigh: isHighOtherBloodSugar(blood?.other_blood_sugar, props.age),
                hasRecord: !!blood && blood.other_blood_sugar != null && blood.other_blood_sugar !== ''
            }
        case 'bp':
            return {
                value: blood && (blood.systolic_pressure || blood.diastolic_pressure) ? formatBp(blood) : '',
                isHigh: isHighBloodPressure(blood),
                hasRecord: !!blood && !!(blood.systolic_pressure || blood.diastolic_pressure)
            }
        case 'western':
            return {
                value: blood?.western_medicine || '',
                isHigh: false,
                hasRecord: !!blood?.western_medicine
            }
        case 'insulin':
            return {
                value: blood?.insulin || '',
                isHigh: false,
                hasRecord: !!blood?.insulin
            }
        case 'breakfast':
            return {
                value: diet?.breakfast || diet?.breakfast_foods ? '✓' : '',
                isHigh: false,
                hasRecord: !!(diet?.breakfast || diet?.breakfast_foods)
            }
        case 'lunch':
            return {
                value: diet?.lunch || diet?.lunch_foods ? '✓' : '',
                isHigh: false,
                hasRecord: !!(diet?.lunch || diet?.lunch_foods)
            }
        case 'dinner':
            return {
                value: diet?.dinner || diet?.dinner_foods ? '✓' : '',
                isHigh: false,
                hasRecord: !!(diet?.dinner || diet?.dinner_foods)
            }
        case 'exercise':
            return {
                value: exercise?.duration ? `${exercise.duration}min` : '',
                isHigh: false,
                hasRecord: !!exercise?.id
            }
        case 'tracking':
            return {
                value: tracking?.content ? summarizeTracking(tracking.content) : '',
                isHigh: false,
                hasRecord: !!tracking?.content
            }
        default:
            return { value: '', isHigh: false, hasRecord: false }
    }
}

async function fetchTracking() {
    if (!diagnosisId.value) {
        bloodRecords.value = []
        dietRecords.value = []
        exerciseRecords.value = []
        trackingNotes.value = []
        return
    }
    const { start, end } = currentRange.value
    if (rangeMode.value === 'custom' && (!start || !end)) return
    const seq = ++requestSeq
    loading.value = true
    try {
        const data: any = await diagnosisTrackingWindow({
            id: diagnosisId.value,
            start_date: start,
            end_date: end
        })
        const noteData: any = await diagnosisTrackingNotes({
            diagnosis_id: diagnosisId.value
        })
        if (seq !== requestSeq) return
        bloodRecords.value = Array.isArray(data?.blood_records) ? data.blood_records : []
        dietRecords.value = Array.isArray(data?.diet_records) ? data.diet_records : []
        exerciseRecords.value = Array.isArray(data?.exercise_records) ? data.exercise_records : []
        trackingNotes.value = Array.isArray(noteData)
            ? noteData.filter((item: any) => visibleDates.value.includes(String(item?.note_date || '')))
            : []
    } catch {
        if (seq === requestSeq) {
            bloodRecords.value = []
            dietRecords.value = []
            exerciseRecords.value = []
            trackingNotes.value = []
        }
    } finally {
        if (seq === requestSeq) loading.value = false
    }
}

function handleRangeModeChange() {
    if (rangeMode.value === 'custom' && !customRange.value) {
        const fallback = computeRange('7')
        customRange.value = [fallback.start, fallback.end]
    }
    fetchTracking()
    void nextTick(updateTableWrapWidth)
}

function handleCustomRangeChange() {
    if (rangeMode.value === 'custom') {
        fetchTracking()
    }
}

function openQuickAdd(kind: DialogKind) {
    if (!canEditDailyRecord.value) return
    const date = visibleDates.value[0] || formatDate(new Date())
    if (kind === 'blood') {
        bloodForm.value = createBloodForm(date)
        bloodDialogVisible.value = true
        return
    }
    if (kind === 'diet') {
        dietForm.value = createDietForm(date)
        dietDialogVisible.value = true
        return
    }
    if (kind === 'tracking') {
        const today = todayDate.value
        const source = trackingByDate.value.get(today)
        trackingForm.value = {
            note_date: today,
            existing_content: String(source?.content || ''),
            content: ''
        }
        trackingDialogVisible.value = true
        return
    }
    exerciseForm.value = createExerciseForm(date)
    exerciseDialogVisible.value = true
}

function handleCellClick(metric: string, date: string) {
    if (!canEditDailyRecord.value) return
    if (['fasting', 'postprandial', 'other', 'bp', 'western', 'insulin'].includes(metric)) {
        const source = bloodByDate.value.get(date)
        bloodForm.value = source ? { ...createBloodForm(date), ...source } : createBloodForm(date)
        bloodDialogVisible.value = true
        return
    }
    if (['breakfast', 'lunch', 'dinner'].includes(metric)) {
        const source = dietByDate.value.get(date)
        dietForm.value = source ? { ...createDietForm(date), ...source } : createDietForm(date)
        dietDialogVisible.value = true
        return
    }
    if (metric === 'tracking') {
        const source = trackingByDate.value.get(date)
        if (!source && date !== todayDate.value) return
        trackingForm.value = {
            note_date: date,
            existing_content: String(source?.content || ''),
            content: ''
        }
        trackingDialogVisible.value = true
        return
    }
    const source = exerciseByDate.value.get(date)
    exerciseForm.value = source ? { ...createExerciseForm(date), ...source } : createExerciseForm(date)
    exerciseDialogVisible.value = true
}

async function submitBlood() {
    if (!bloodForm.value.record_date) {
        feedback.msgWarning('请选择记录日期')
        return
    }
    bloodSubmitting.value = true
    try {
        if (bloodForm.value.id) {
            await bloodRecordEdit(bloodForm.value)
        } else {
            await bloodRecordAdd(bloodForm.value)
        }
        bloodDialogVisible.value = false
        await fetchTracking()
    } finally {
        bloodSubmitting.value = false
    }
}

async function submitDiet() {
    if (!dietForm.value.record_date) {
        feedback.msgWarning('请选择记录日期')
        return
    }
    dietSubmitting.value = true
    try {
        if (dietForm.value.id) {
            await dietRecordEdit(dietForm.value)
        } else {
            await dietRecordAdd(dietForm.value)
        }
        dietDialogVisible.value = false
        await fetchTracking()
    } finally {
        dietSubmitting.value = false
    }
}

async function submitExercise() {
    if (!exerciseForm.value.record_date) {
        feedback.msgWarning('请选择记录日期')
        return
    }
    if (!exerciseForm.value.exercise_type) {
        feedback.msgWarning('请选择运动类型')
        return
    }
    if (!exerciseForm.value.duration) {
        feedback.msgWarning('请输入运动时长')
        return
    }
    exerciseSubmitting.value = true
    try {
        if (exerciseForm.value.id) {
            await exerciseRecordEdit(exerciseForm.value)
        } else {
            await exerciseRecordAdd(exerciseForm.value)
        }
        exerciseDialogVisible.value = false
        await fetchTracking()
    } finally {
        exerciseSubmitting.value = false
    }
}

async function submitTracking() {
    if (!trackingForm.value.note_date) {
        feedback.msgWarning('请选择记录日期')
        return
    }
    if (!trackingCanSubmit.value) {
        feedback.msgWarning('仅支持给今天追加跟踪备注')
        return
    }
    const content = trackingForm.value.content.trim()
    if (!content) {
        feedback.msgWarning('请输入跟踪备注')
        return
    }
    trackingSubmitting.value = true
    try {
        await diagnosisAddTrackingNote({
            diagnosis_id: diagnosisId.value,
            tracking_content: content
        })
        trackingDialogVisible.value = false
        await fetchTracking()
    } finally {
        trackingSubmitting.value = false
    }
}

function summarizeTracking(content: string) {
    return splitTrackingLines(content)[0] || ''
}

function splitTrackingLines(content: string) {
    return content.split('\n').map((line) => line.trim()).filter(Boolean)
}

function getTrackingContent(date: string) {
    return String(trackingByDate.value.get(date)?.content || '')
}

function getTrackingPreview(content: string) {
    return summarizeTracking(content)
}

function isCellClickable(metric: string, date: string) {
    if (!canEditDailyRecord.value) return false
    if (metric !== 'tracking') return true
    return date === todayDate.value || !!getTrackingContent(date)
}

watch(
    () => props.diagnosisId,
    (value) => {
        if (value) {
            fetchTracking()
        }
        void nextTick(updateTableWrapWidth)
    }
)

onMounted(() => {
    if (props.diagnosisId) {
        fetchTracking()
    }
    void nextTick(updateTableWrapWidth)
    window.addEventListener('resize', updateTableWrapWidth)
})

onUnmounted(() => {
    window.removeEventListener('resize', updateTableWrapWidth)
})

defineExpose({ refresh: fetchTracking })
</script>

<style lang="scss" scoped>
.daily-matrix {
    padding: 16px;

    &__toolbar {
        display: flex;
        justify-content: space-between;
        gap: 12px;
        align-items: center;
        flex-wrap: wrap;
        margin-bottom: 12px;
    }

    &__toolbar-left,
    &__toolbar-right {
        display: flex;
        align-items: center;
        gap: 8px;
        flex-wrap: wrap;
    }

    &__table {
        width: 100%;
    }

    &__table-wrap {
        width: 100%;
    }

    &__chart {
        margin-top: 16px;
        padding: 16px 18px;
        border: 1px solid var(--el-border-color-lighter);
        border-radius: 10px;
        background: linear-gradient(180deg, #ffffff 0%, #f8fafc 100%);
    }

    &__chart-canvas {
        height: 280px;
        width: 100%;
    }

    &__cell {
        min-height: 32px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: 2px;
        width: 100%;
        color: var(--el-text-color-regular);

        &.is-clickable {
            cursor: pointer;
        }

        &.is-empty {
            color: var(--el-text-color-placeholder);
        }

        &.is-high {
            color: #dc2626;
            font-weight: 700;
        }
    }

    &__cell-up {
        color: #dc2626;
        font-size: 13px;
    }

    &__todo {
        margin-top: 16px;
    }

    &__section-title {
        font-size: 14px;
        font-weight: 600;
        margin-bottom: 12px;
        color: var(--el-text-color-primary);
    }

    &__tracking-existing {
        width: 100%;
        max-height: 180px;
        overflow: auto;
        padding: 8px 10px;
        border: 1px solid var(--el-border-color);
        border-radius: 6px;
        background: var(--el-fill-color-light);
    }

    &__tracking-line {
        font-size: 12.5px;
        line-height: 1.6;
        color: var(--el-text-color-regular);
        word-break: break-word;
    }

    &__tracking-preview {
        display: block;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        font-size: 12px;
        width: 100%;
        text-align: left;
    }

    &__tracking-tooltip {
        max-width: 320px;
    }

    &__tracking-tooltip-line {
        font-size: 12.5px;
        line-height: 1.6;
        word-break: break-word;
    }
}

@media (max-width: 768px) {
    .daily-matrix {
        padding: 12px;

        &__chart {
            padding: 12px;
        }

        &__chart-canvas {
            height: 240px;
        }
    }
}
</style>
