<template>
    <ParentPage active="reports" :show-tab="false" :use-scroll-view="false">
        <ParentFilterRow :items="filterItems" @change="onFilterChange" />

        <view class="module-section">
            <ParentCard title="错题知识点占比" subtitle="按错题占比识别最近需要优先补强的知识点">
                <view v-if="pageLoading" class="loading-wrap">
                    <xy-Empty type="loading" content="加载中..." />
                </view>
                <scroll-view
                    v-else-if="wrongRatioList.length"
                    class="ratio-scroll"
                    scroll-y
                    :show-scrollbar="false"
                    :style="ratioScrollStyle"
                >
                    <view class="ratio-layout">
                        <view class="ratio-main">
                            <view class="ratio-total">
                                <text class="ratio-number">{{ mainWrongPercent }}%</text>
                                <text class="ratio-label">最高错题占比</text>
                            </view>
                            <view
                                v-for="item in wrongRatioList"
                                :key="`bar-${item.kpointId}`"
                                class="ratio-bar"
                            >
                                <view class="ratio-fill" :class="item.tone" :style="{ width: `${item.ratioPercent}%` }"></view>
                            </view>
                        </view>
                        <view class="legend-list">
                            <view v-for="item in wrongRatioList" :key="item.kpointId" class="legend-item">
                                <view class="legend-dot" :class="item.tone"></view>
                                <text class="legend-name ellipsis">{{ item.kpointName }}</text>
                                <text class="legend-percent">{{ formatPercent(item.ratioPercent) }}%</text>
                            </view>
                        </view>
                    </view>
                </scroll-view>
                <xy-Empty v-else type="task" :content="emptyTip" />
            </ParentCard>
        </view>

        <view class="module-section">
            <ParentCard title="知识点得分" subtitle="可切换得分等级，快速定位当前薄弱段">
                <view class="level-tabs">
                    <view
                        v-for="level in scoreLevels"
                        :key="level.key"
                        class="level-tab"
                        :class="{ active: activeLevel === level.key }"
                        @click="activeLevel = level.key"
                    >
                        {{ level.label }}
                    </view>
                </view>

                <view v-if="pageLoading" class="loading-wrap">
                    <xy-Empty type="loading" content="加载中..." />
                </view>
                <view v-else-if="levelKnowledge.length" class="score-table-wrap">
                    <view class="score-row table-head">
                        <text>知识点</text>
                        <text>满分</text>
                        <text>得分</text>
                    </view>
                    <scroll-view class="score-table-scroll" scroll-y :show-scrollbar="false" :style="scoreTableScrollStyle">
                        <view v-for="item in levelKnowledge" :key="`${item.kpointId}-${activeLevel}`" class="score-row">
                            <text class="knowledge-name ellipsis">{{ item.kpointName }}</text>
                            <text>{{ item.fullScore }}</text>
                            <text class="score-value">{{ item.score }}<text class="score-rate">({{ formatPercent(item.scoreRatePercent) }}%)</text></text>
                        </view>
                    </scroll-view>
                </view>
                <xy-Empty v-else type="learn" content="当前等级暂无知识点" />
            </ParentCard>
        </view>

        <view class="module-section">
            <ParentCard title="得分能力" subtitle="综合最近多次练习得分，观察能力变化和稳定性">
                <view v-if="pageLoading" class="loading-wrap">
                    <xy-Empty type="loading" content="加载中..." />
                </view>
                <template v-else-if="abilityHasContent">
                    <view v-if="abilityHasChartData" class="ucharts-wrap">
                        <qiun-data-charts
                            class="ability-chart"
                            type="line"
                            canvasId="parentAbilityTrendCanvas2dLineChart"
                            background="rgba(255,255,255,0)"
                            :canvas2d="false"
                            :in-scroll-view="false"
                            :ontouch="false"
                            :disable-scroll="true"
                            :reload="chartReload"
                            :reshow="chartReshow"
                            :opts="abilityChartOpts"
                            :chartData="abilityChartData"
                        />
                    </view>

                    <view class="summary-grid">
                        <view v-for="item in abilitySummaryList" :key="item.label" class="summary-item">
                            <text class="summary-label">{{ item.label }}</text>
                            <text class="summary-value">{{ item.value }}</text>
                            <text class="summary-desc">{{ item.desc }}</text>
                        </view>
                    </view>
                </template>
                <xy-Empty v-else type="learn" :content="abilityEmptyTip" />
            </ParentCard>
        </view>
    </ParentPage>
</template>

<script setup lang="ts">
import { computed, nextTick, ref, watch } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import { storeToRefs } from 'pinia';
import {
    getKpointScore,
    getScoreAbility,
    getWrongKpointRatio,
    type KpointScoreLevel,
    type ScoreAbilityPoint,
    type ScoreAbilityResult,
    type WrongKpointRatioItem,
} from '@/api/parent';
import { useParentStore } from '@/state/modules/parent';
import { useUserStore } from '@/state/modules/user';
import { formatTime } from '@/utils/format';
import { SUBJECT_PICKER_OPTIONS } from '@/utils/subject';
import ParentCard from '../components/ParentCard.vue';
import ParentFilterRow from '../components/ParentFilterRow.vue';
import ParentPage from '../components/ParentPage.vue';

const categoryOptions = ['全部类型', '周作业', '月考'];

type ScoreLevel = 'weak' | 'pass' | 'good' | 'excellent';
type RatioTone = 'blue' | 'orange' | 'green' | 'rose';

interface WrongRatioViewItem {
    kpointId: number;
    kpointName: string;
    ratioPercent: number;
    tone: RatioTone;
}

interface ScoreViewItem {
    kpointId: number;
    kpointName: string;
    fullScore: number;
    score: number;
    scoreRatePercent: number;
}

interface AbilityTrendViewItem {
    date: string;
    score: number;
}

interface AbilitySummaryViewItem {
    label: string;
    value: string;
    desc: string;
}

const RATIO_TONES: RatioTone[] = ['blue', 'orange', 'green', 'rose'];

/** 列表区域高度区间（rpx） */
const MODULE_SCROLL_MIN_RPX = 280;
const MODULE_SCROLL_MAX_RPX = 520;
const SCORE_ROW_RPX = 76;

const clampModuleScrollHeight = (contentRpx: number) => {
    const heightRpx = Math.max(MODULE_SCROLL_MIN_RPX, Math.min(MODULE_SCROLL_MAX_RPX, contentRpx));
    return `${heightRpx}rpx`;
};

const LEVEL_CODE_MAP: Record<ScoreLevel, number> = {
    excellent: 1,
    good: 2,
    pass: 3,
    weak: 4,
};

const userStore = useUserStore();
const parentStore = useParentStore();
const { activeChild } = storeToRefs(parentStore);

const subjectIndex = ref(0);
const categoryIndex = ref(0);
const activeLevel = ref<ScoreLevel>('weak');
const pageLoading = ref(false);

const wrongRatioList = ref<WrongRatioViewItem[]>([]);
const scoreLevelsData = ref<KpointScoreLevel[]>([]);
const abilityTrendList = ref<AbilityTrendViewItem[]>([]);
const abilitySummaryList = ref<AbilitySummaryViewItem[]>([]);
const abilityHasContent = ref(false);
const abilityHasChartData = ref(false);

const filterItems = computed(() => [
    { key: 'subject', range: SUBJECT_PICKER_OPTIONS.map((item) => item.label), value: subjectIndex.value },
    { key: 'category', range: categoryOptions, value: categoryIndex.value },
]);

const emptyTip = computed(() => {
    if (!activeChild.value.id) return '请先绑定并选择孩子';
    return '暂无符合条件的知识点数据';
});

const abilityEmptyTip = computed(() => {
    if (!activeChild.value.id) return '请先绑定并选择孩子';
    return '暂无得分能力数据';
});

const mainWrongPercent = computed(() => {
    if (!wrongRatioList.value.length) return 0;
    return Math.max(...wrongRatioList.value.map((item) => item.ratioPercent));
});

const scoreLevels: { key: ScoreLevel; label: string }[] = [
    { key: 'weak', label: '薄弱' },
    { key: 'pass', label: '合格' },
    { key: 'good', label: '良好' },
    { key: 'excellent', label: '优秀' },
];

const ratioScrollStyle = computed(() => {
    const count = wrongRatioList.value.length;
    const mainHeight = 116 + count * 30;
    const legendHeight = count * 46;
    return { height: clampModuleScrollHeight(Math.max(mainHeight, legendHeight)) };
});

const levelKnowledge = computed<ScoreViewItem[]>(() => {
    const levelCode = LEVEL_CODE_MAP[activeLevel.value];
    const level = scoreLevelsData.value.find((item) => item.levelCode === levelCode);
    return (level?.items || []).map((item) => ({
        kpointId: item.kpointId ?? 0,
        kpointName: item.kpointName || '--',
        fullScore: item.fullScore ?? 0,
        score: item.actualScore ?? 0,
        scoreRatePercent: item.scoreRatePercent ?? 0,
    }));
});

const scoreTableScrollStyle = computed(() => {
    const rows = levelKnowledge.value.length;
    return { height: clampModuleScrollHeight(rows * SCORE_ROW_RPX) };
});

const formatPercent = (value?: number) => {
    const num = Number(value);
    if (!Number.isFinite(num)) return '0';
    return Number.isInteger(num) ? String(num) : num.toFixed(1);
};

const mapWrongRatioItems = (items: WrongKpointRatioItem[] = []): WrongRatioViewItem[] =>
    items.map((item, index) => ({
        kpointId: item.kpointId ?? index,
        kpointName: item.kpointName || '--',
        ratioPercent: item.ratioPercent ?? 0,
        tone: RATIO_TONES[index % RATIO_TONES.length],
    }));

const formatAbilityDate = (value?: string) => {
    if (!value) return '--';
    const formatted = formatTime(value, 'MM-DD');
    return formatted || value;
};

const normalizeAbilityScore = (item: ScoreAbilityPoint) => {
    if (!item.hasData) return 0;
    const score = Number(item.scoreAbility);
    return Number.isFinite(score) ? score : 0;
};

const mapAbilityTrendItems = (points: ScoreAbilityPoint[] = []): AbilityTrendViewItem[] =>
    points.map((item) => ({
        date: formatAbilityDate(item.statDate),
        score: normalizeAbilityScore(item),
    }));

const hasAbilityChartData = (points: ScoreAbilityPoint[] = []) => points.length > 0;

const mapAbilitySummary = (data?: ScoreAbilityResult): AbilitySummaryViewItem[] => {
    const overallScore = data?.overallScoreAbility;
    const overallDesc =
        overallScore != null
            ? `综合得分能力 ${formatPercent(overallScore)} 分`
            : '暂无评估数据';
    const periodDesc =
        data?.startDate && data?.endDate
            ? `统计周期 ${formatAbilityDate(data.startDate)} ~ ${formatAbilityDate(data.endDate)}`
            : '暂无稳定性分析';

    return [
        {
            label: '得分能力综合评估',
            value: data?.assessmentName || '--',
            desc: overallDesc,
        },
        {
            label: '得分能力稳定性',
            value: data?.stabilityName || '--',
            desc: periodDesc,
        },
    ];
};

const getSelectedSubjectId = () => SUBJECT_PICKER_OPTIONS[subjectIndex.value]?.value;

const fetchAnalysisData = async () => {
    const userId = activeChild.value.id;
    const subjectId = getSelectedSubjectId();

    if (!userId || !subjectId) {
        wrongRatioList.value = [];
        scoreLevelsData.value = [];
        abilityTrendList.value = [];
        abilitySummaryList.value = [];
        abilityHasContent.value = false;
        abilityHasChartData.value = false;
        return;
    }

    pageLoading.value = true;
    try {
        const params = { subjectId, userId };
        const [ratioRes, scoreRes, abilityRes] = await Promise.all([
            getWrongKpointRatio(params),
            getKpointScore(params),
            getScoreAbility(params),
        ]);
        wrongRatioList.value = mapWrongRatioItems(ratioRes.data?.items);
        scoreLevelsData.value = scoreRes.data?.levels || [];
        abilityTrendList.value = mapAbilityTrendItems(abilityRes.data?.points);
        abilitySummaryList.value = mapAbilitySummary(abilityRes.data);
        abilityHasChartData.value = hasAbilityChartData(abilityRes.data?.points);
        abilityHasContent.value = abilityHasChartData.value || !!abilityRes.data?.assessmentName;
    } catch (err) {
        console.error('[parent-analysis] fetch err', err);
        wrongRatioList.value = [];
        scoreLevelsData.value = [];
        abilityTrendList.value = [];
        abilitySummaryList.value = [];
        abilityHasContent.value = false;
        abilityHasChartData.value = false;
    } finally {
        pageLoading.value = false;
        await refreshChart();
    }
};

const onFilterChange = (payload: { key: string; value: number }) => {
    if (payload.key === 'subject') {
        subjectIndex.value = payload.value;
        return;
    }
    if (payload.key === 'category') {
        categoryIndex.value = payload.value;
    }
};

watch([subjectIndex, categoryIndex, () => activeChild.value.id], () => {
    fetchAnalysisData();
});

const buildAbilityChartData = () => ({
    categories: abilityTrendList.value.map((item) => item.date),
    series: [
        {
            name: '得分能力',
            data: abilityTrendList.value.map((item) => item.score),
            color: '#0891b2',
        },
    ],
});

const abilityChartData = ref<Record<string, unknown>>({ categories: [], series: [] });
const chartReshow = ref(false);
const chartReload = ref(false);

const refreshChart = async () => {
    if (!abilityHasChartData.value) {
        abilityChartData.value = { categories: [], series: [] };
        return;
    }
    abilityChartData.value = JSON.parse(JSON.stringify(buildAbilityChartData()));
    await nextTick();
    setTimeout(() => {
        chartReload.value = !chartReload.value;
        chartReshow.value = !chartReshow.value;
    }, 320);
};

const abilityChartMin = computed(() => {
    if (!abilityTrendList.value.length) return 0;
    const minScore = Math.min(...abilityTrendList.value.map((item) => item.score));
    return Math.max(0, Math.floor(minScore / 10) * 10 - 10);
});

onShow(async () => {
    try {
        if (!userStore.userInfo.id) {
            await userStore.fetchParentUserInfo();
        }
        await parentStore.fetchBindChildren(userStore.userInfo.id);
    } catch {
        /* ignore */
    }
    await fetchAnalysisData();
});

const abilityChartOpts = computed(() => {
    const pointCount = abilityTrendList.value.length || 30;
    const labelCount = Math.min(6, Math.max(4, Math.ceil(pointCount / 5)));

    return {
        color: ['#0891b2'],
        padding: [18, 12, 8, 12],
        enableScroll: false,
        dataLabel: false,
        legend: { show: false },
        xAxis: {
            disableGrid: false,
            gridColor: '#eef2f7',
            fontColor: '#64748b',
            fontSize: 10,
            boundaryGap: 'justify',
            labelCount,
        },
        yAxis: {
            gridType: 'dash',
            dashLength: 2,
            gridColor: '#eef2f7',
            data: [
                {
                    min: abilityChartMin.value,
                    max: 100,
                    splitNumber: 4,
                    fontColor: '#94a3b8',
                    fontSize: 10,
                },
            ],
        },
        extra: {
            line: {
                type: 'curve',
                width: 3,
                activeType: 'hollow',
            },
            markLine: {
                type: 'dash',
                dashLength: 6,
                data: [
                    { value: 85, lineColor: 'rgba(244, 63, 94, 0.32)', showLabel: true, labelText: '优秀' },
                    { value: 70, lineColor: 'rgba(244, 63, 94, 0.28)', showLabel: true, labelText: '良好' },
                    { value: 60, lineColor: 'rgba(244, 63, 94, 0.22)', showLabel: true, labelText: '一般' },
                ],
            },
        },
    };
});

</script>

<style lang="scss" scoped>
.module-section {
    margin-top: 44rpx;
    width: 100%;
    max-width: 100%;
    overflow-x: hidden;
}

.filter-row + .module-section {
    margin-top: 36rpx;
}

.loading-wrap {
    padding: 24rpx 0;
}

.ratio-scroll {
    min-height: 280rpx;
    max-height: 520rpx;
}

.ratio-layout {
    display: flex;
    align-items: flex-start;
    gap: 28rpx;
    width: 100%;
    max-width: 100%;
}

.ratio-main {
    width: 232rpx;
    flex-shrink: 0;
}

.ratio-total {
    min-height: 116rpx;
    border-radius: 28rpx;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: linear-gradient(180deg, #ecfeff 0%, #ffffff 100%);
    box-shadow: inset 0 -2rpx 0 rgba(34, 211, 238, 0.24);
}

.ratio-number {
    color: #164e63;
    font-size: 42rpx;
    font-weight: 900;
}

.ratio-label {
    margin-top: 2rpx;
    color: #64748b;
    font-size: 20rpx;
}

.ratio-bar {
    height: 16rpx;
    margin-top: 14rpx;
    border-radius: 999rpx;
    overflow: hidden;
    background: #e2e8f0;
}

.ratio-fill {
    height: 100%;
    border-radius: 999rpx;

    &.blue { background: #3b82f6; }
    &.orange { background: #f97316; }
    &.green { background: #22c55e; }
    &.rose { background: #f43f5e; }
}

.legend-list {
    flex: 1;
    min-width: 0;
}

.legend-item {
    display: flex;
    align-items: center;
    gap: 12rpx;
    min-height: 46rpx;
    color: #164e63;
    font-size: 24rpx;
    font-weight: 700;
}

.legend-dot {
    width: 16rpx;
    height: 16rpx;
    border-radius: 50%;
    flex-shrink: 0;

    &.blue { background: #3b82f6; }
    &.orange { background: #f97316; }
    &.green { background: #22c55e; }
    &.rose { background: #f43f5e; }
}

.legend-name {
    flex: 1;
}

.legend-percent {
    color: #0891b2;
}

.level-tabs {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 14rpx;
    margin-bottom: 20rpx;
}

.level-tab {
    height: 64rpx;
    border: 2rpx solid #e2e8f0;
    border-radius: 22rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #475569;
    background: #ffffff;
    font-size: 24rpx;
    font-weight: 800;

    &.active {
        border-color: #0891b2;
        color: #ffffff;
        background: linear-gradient(180deg, #22d3ee 0%, #0891b2 100%);
        box-shadow: 0 10rpx 20rpx rgba(8, 145, 178, 0.2);
    }
}

.score-table-wrap {
    border: 2rpx solid #e2e8f0;
    border-radius: 24rpx;
    overflow: hidden;
}

.score-table-scroll {
    min-height: 280rpx;
    max-height: 520rpx;
}

.score-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 112rpx 150rpx;
    align-items: center;
    min-height: 76rpx;
    padding: 0 22rpx;
    color: #164e63;
    font-size: 24rpx;
    text-align: center;
    border-top: 2rpx solid #f1f5f9;

    &:first-child {
        border-top: 0;
    }

    > text,
    > .knowledge-name {
        min-width: 0;
    }
}

.table-head {
    color: #475569;
    background: #f8fafc;
    font-weight: 900;
}

.knowledge-name {
    text-align: left;
}

.score-value {
    color: #ea580c;
    font-weight: 900;
}

.score-rate {
    margin-left: 2rpx;
    font-size: 22rpx;
    font-weight: 700;
}

.ucharts-wrap {
    width: 100%;
    max-width: 100%;
    height: 360rpx;
    margin-top: 4rpx;
    overflow: hidden;
    position: relative;
}

.ability-chart {
    display: block;
    width: 100% !important;
    max-width: 100%;
    height: 100%;
}

.summary-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 16rpx;
    margin-top: 26rpx;
}

.summary-item {
    padding: 18rpx;
    border-radius: 24rpx;
    background: #f8fafc;
    text-align: center;
}

.summary-label,
.summary-desc {
    display: block;
    color: #64748b;
    font-size: 22rpx;
    line-height: 1.45;
}

.summary-value {
    display: block;
    margin: 8rpx 0;
    color: #0891b2;
    font-size: 32rpx;
    font-weight: 900;
}
</style>
