<template>
    <template v-if="rows.length > 0">
        <div :style="{ width: '100%', height: containerHeight + 'px' }">
            <div ref="elRef" style="width: 100%; height: 100%;"></div>
        </div>
    </template>
    <template v-else>
        <el-empty description="暂无词汇数据或接口未返回" />
    </template>
</template>

<script setup>
import { defineProps, ref, onMounted, onUnmounted, watch, computed } from 'vue'
import { getStudentWordMastery } from '@/api/student'

const props = defineProps({
    studentId: { type: [Number, String], required: true },
    columns: { type: Number, default: 50 }
})

const elRef = ref(null)
let chart = null
let echartsLib = null
const rows = ref([])
const loading = ref(false)
const error = ref(null)
const containerHeight = computed(() => {
    const count = rows.value.length
    const cols = Math.max(1, Number(props.columns) || 50)
    const r = Math.ceil(count / cols)
    const cell = 12
    const padding = 60
    return Math.max(180, r * cell + padding)
})

function toGrid(data, columns) {
    const arr = Array.isArray(data) ? data.slice() : []
    arr.sort((a, b) => {
        const av = Number(a.memoryStrength) || 0
        const bv = Number(b.memoryStrength) || 0
        // 高分在前，让上方更绿
        return bv - av
    })
    const grid = []
    for (let i = 0; i < arr.length; i++) {
        const row = Math.floor(i / columns)
        const col = i % columns
        const it = arr[i]
        grid.push([col, row, Number(it.memoryStrength) || 0, it.word, Number(it.reviewCount) || 0, it.updateTime || ''])
    }
    return grid
}

function getMinMax(data) {
    let min = Infinity
    let max = -Infinity
    for (const it of data) {
        const v = Number(it.memoryStrength) || 0
        if (v < min) min = v
        if (v > max) max = v
    }
    if (!isFinite(min)) min = 0
    if (!isFinite(max)) max = 0
    const absMax = Math.max(Math.abs(min), Math.abs(max), 1)
    return { min: -absMax, max: absMax }
}

function buildOption(gridData, min, max, columns) {
    const rowCount = gridData.reduce((acc, cur) => Math.max(acc, cur[1]), 0) + 1
    const xCats = Array.from({ length: columns }, (_, i) => String(i + 1))
    const yCats = Array.from({ length: rowCount }, (_, i) => String(i + 1))
    return {
        tooltip: {
            formatter: (p) => {
                const [x, y, val, word, review, time] = p.data || []
                return [
                    `词汇：${word || ''}`,
                    `记忆强度：${val}`,
                    `复习次数：${review}`,
                    time ? `更新时间：${time}` : ''
                ].filter(Boolean).join('<br/>')
            }
        },
        grid: { left: 20, right: 20, top: 20, bottom: 80 },
        xAxis: {
            type: 'category',
            data: xCats,
            axisLine: { show: false },
            axisTick: { show: false },
            axisLabel: { show: false }
        },
        yAxis: {
            type: 'category',
            data: yCats,
            axisLine: { show: false },
            axisTick: { show: false },
            axisLabel: { show: false }
        },
        visualMap: {
            min,
            max,
            dimension: 2,
            orient: 'horizontal',
            left: 'center',
            bottom: 0,
            text: ['熟悉', '生疏'],
            inRange: {
                color: ['#d64f4f', '#f59e0b', '#c0c0c0', '#86efac', '#22c55e']
            },
            calculable: true
        },
        series: [{
            name: '掌握度',
            type: 'heatmap',
            data: gridData,
            encode: { x: 0, y: 1, value: 2 },
            emphasis: { 
                itemStyle: { 
                    borderColor: '#111827', 
                    borderWidth: 1.2,
                    shadowBlur: 6,
                    shadowColor: 'rgba(0,0,0,0.15)'
                } 
            },
            itemStyle: { 
                borderColor: '#e5e7eb', 
                borderWidth: 1,
                opacity: 0.95 
            }
        }]
    }
}

function resize() {
    if (chart) chart.resize()
}

async function ensureEcharts() {
    try {
        const mod = await import('echarts')
        echartsLib = mod
    } catch (e) {
        if (window.echarts) {
            echartsLib = window.echarts
        } else {
            await new Promise(resolve => {
                const s = document.createElement('script')
                s.src = 'https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js'
                s.onload = resolve
                document.head.appendChild(s)
            })
            echartsLib = window.echarts
        }
    }
}

async function render() {
    if (!elRef.value) return
    await ensureEcharts()
    if (!echartsLib) return
    if (!chart) {
        chart = echartsLib.init(elRef.value)
        window.addEventListener('resize', resize)
    }
    const cols = Math.max(1, Number(props.columns) || 50)
    const gridData = toGrid(rows.value, cols)
    const { min, max } = getMinMax(rows.value)
    const option = buildOption(gridData, min, max, cols)
    chart.setOption(option)
}

async function fetch() {
    if (props.studentId === undefined || props.studentId === null) return
    loading.value = true
    try {
        const res = await getStudentWordMastery(Number(props.studentId))
        const d = res?.data?.data ?? []
        rows.value = Array.isArray(d) ? d : []
    } catch (e) {
        error.value = e?.message || '加载失败'
        rows.value = []
    } finally {
        loading.value = false
    }
}

onMounted(async () => {
    await fetch()
    await render()
})

onUnmounted(() => {
    window.removeEventListener('resize', resize)
    if (chart) {
        chart.dispose()
        chart = null
    }
})

watch(() => props.studentId, async () => {
    await fetch()
    await render()
})

watch(rows, async () => {
    if (rows.value.length > 0) {
        await render()
    } else {
        if (chart) chart.clear()
    }
})
</script>

<style scoped>
</style>
