import { BaseDrawService } from '../../core/draw/baseDraw';
import NumberFindDraw from '../shared/service/numberFindDraw';
import CountMatchDraw from '../shared/service/countMatchDraw';
import NumberColorDraw from '../shared/service/numberColorDraw';
import AdditionDraw from '../shared/service/additionDraw';
import MissingNumberDraw from '../shared/service/missingNumberDraw';
import CompareDraw from '../shared/service/compareDraw';
import CountingSelectDraw from '../shared/service/countingSelectDraw';
import NumberDecomposeDraw from '../shared/service/numberDecomposeDraw';
import NumberSortDraw from '../shared/service/numberSortDraw';
import NumberObjectMatchDraw from '../shared/service/numberObjectMatchDraw';
import MakeTenDraw from '../shared/service/makeTenDraw';
import BreakTenDraw from '../shared/service/breakTenDraw';
import FlatTenDraw from '../shared/service/flatTenDraw';
import OneDigitAdditionDraw from '../shared/service/oneDigitAdditionDraw';
import CalculationPracticeDraw from '../shared/service/calculationPracticeDraw';
import MultiplicationTableDraw from '../shared/service/multiplicationTableDraw';

import { getRandomNumberColor, getNumberColors, NUMBER_COLORS } from '../../constants/colors';

// ─── Types ───

export interface MathTypeAction {
    value: string;
    label: string;
}

export interface MathTypeConfig {
    id: string;
    title: string;
    subTitle: string;
    icon: string;
    actionsTitle?: string;
    actions?: MathTypeAction[];
    defaultMode?: string;
    hasNumberGrid?: boolean;
    getTitle?: (mode: string) => string;
    getSubTitle?: (mode: string) => string;
    createDrawService: (
        canvas: Canvas,
        ctx: RenderingContext,
        options?: Record<string, any>,
    ) => BaseDrawService;
    generateData: (mode?: string, extra?: any) => any;
    drawArgs?: (data: any, mode: string) => any[];
    /** 需要根据 functionId 决定不同的 actions/DrawService 的复合类型 */
    variants?: Record<string, {
        title: string;
        subTitle: string;
        actions?: MathTypeAction[];
        defaultMode?: string;
        createDrawService?: (canvas: Canvas, ctx: RenderingContext, options?: Record<string, any>) => BaseDrawService;
    }>;
}

// ─── Data Generators ───

function generateNumberFindData(_mode?: string, extra?: any) {
    const selectedNumber = extra?.selectedNumber || Math.floor(Math.random() * 10) + 1;
    return { selectedNumber };
}

function generateCountMatchData(mode?: string) {
    const availableNumbers = Array.from({ length: 10 }, (_, i) => i + 1);
    const leftNumbers: number[] = [];
    const pool = [...availableNumbers];
    for (let i = 0; i < 5; i++) {
        const idx = Math.floor(Math.random() * pool.length);
        leftNumbers.push(pool.splice(idx, 1)[0]);
    }
    const rightNumbers = [...leftNumbers];
    for (let i = rightNumbers.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [rightNumbers[i], rightNumbers[j]] = [rightNumbers[j], rightNumbers[i]];
    }
    return { leftNumbers, rightNumbers, _drawMode: mode || 'twelve-animals' };
}

function generateNumberColorData(mode?: string) {
    const availableNumbers = Array.from({ length: 10 }, (_, i) => i + 1);
    const numbers: number[] = [];
    const pool = [...availableNumbers];
    for (let i = 0; i < 6; i++) {
        const idx = Math.floor(Math.random() * pool.length);
        numbers.push(pool.splice(idx, 1)[0]);
    }
    return { numbers, _drawMode: mode || 'caterpillar' };
}

function generateAdditionData(mode?: string) {
    const type = mode || 'addition-5';
    const problems: Array<{ type: 'addition' | 'subtraction'; left: number; right: number; result: number }> = [];

    for (let i = 0; i < 5; i++) {
        if (type === 'addition-5') {
            const left = Math.floor(Math.random() * 4) + 1;
            const right = Math.floor(Math.random() * (5 - left)) + 1;
            problems.push({ type: 'addition', left, right, result: left + right });
        } else if (type === 'addition-10') {
            const left = Math.floor(Math.random() * 9) + 1;
            const right = Math.floor(Math.random() * (10 - left)) + 1;
            problems.push({ type: 'addition', left, right, result: left + right });
        } else if (type === 'subtraction-10') {
            const left = Math.floor(Math.random() * 10) + 1;
            const right = Math.floor(Math.random() * (left - 1)) + 1;
            problems.push({ type: 'subtraction', left, right, result: left - right });
        } else {
            if (Math.random() < 0.5) {
                const left = Math.floor(Math.random() * 9) + 1;
                const right = Math.floor(Math.random() * (10 - left)) + 1;
                problems.push({ type: 'addition', left, right, result: left + right });
            } else {
                const left = Math.floor(Math.random() * 10) + 1;
                const right = Math.floor(Math.random() * (left - 1)) + 1;
                problems.push({ type: 'subtraction', left, right, result: left - right });
            }
        }
    }
    return { problems };
}

function generateMissingNumberData(mode?: string) {
    const maxNumber = parseInt(mode || '10') || 10;
    const gridMap: Record<number, number> = { 10: 3, 20: 2, 40: 2, 50: 2, 80: 1, 100: 1, 120: 1 };
    const gridCount = gridMap[maxNumber] || 1;

    const grids: Array<{ numbers: (number | null)[]; colors: (string | null)[] }> = [];
    for (let g = 0; g < gridCount; g++) {
        const total = maxNumber;
        const numbers = Array.from({ length: total }, (_, i) => i + 1);
        const hideCount = Math.floor(total * (0.4 + Math.random() * 0.2));
        const hidden = new Set<number>();
        while (hidden.size < hideCount) hidden.add(Math.floor(Math.random() * total));

        const gridNumbers: (number | null)[] = numbers.map((n, i) => hidden.has(i) ? null : n);
        const gridColors: (string | null)[] = gridNumbers.map((n) => n ? getRandomNumberColor() : null);
        grids.push({ numbers: gridNumbers, colors: gridColors });
    }
    return { grids, maxNumber };
}

function generateCompareData() {
    const problems: Array<{
        leftCount: number; rightCount: number;
        leftImageIndex: number; rightImageIndex: number;
        imageType: 'fruits' | 'twelve-animals';
    }> = [];

    for (let i = 0; i < 12; i++) {
        const imageType: 'fruits' | 'twelve-animals' = Math.random() < 0.5 ? 'fruits' : 'twelve-animals';
        const maxIdx = imageType === 'fruits' ? 22 : 12;
        problems.push({
            leftCount: Math.floor(Math.random() * 10) + 1,
            rightCount: Math.floor(Math.random() * 10) + 1,
            leftImageIndex: Math.floor(Math.random() * maxIdx) + 1,
            rightImageIndex: Math.floor(Math.random() * maxIdx) + 1,
            imageType,
        });
    }
    return { problems };
}

function generateCountingSelectData(_mode?: string, extra?: any) {
    const isFillMode = extra?.functionId === 'counting-fill';
    const problems: Array<{
        count: number; imageIndex: number; imageType: 'fruits' | 'twelve-animals';
        options?: number[]; correctIndex?: number;
    }> = [];

    for (let i = 0; i < 9; i++) {
        const imageType: 'fruits' | 'twelve-animals' = Math.random() < 0.5 ? 'fruits' : 'twelve-animals';
        const maxIdx = imageType === 'fruits' ? 22 : 12;
        const count = Math.floor(Math.random() * 10) + 1;
        const problem: any = { count, imageIndex: Math.floor(Math.random() * maxIdx) + 1, imageType };

        if (!isFillMode) {
            const options: number[] = [];
            const correctIndex = Math.floor(Math.random() * 3);
            for (let j = 0; j < 3; j++) {
                if (j === correctIndex) { options.push(count); }
                else { let w; do { w = Math.floor(Math.random() * 10) + 1; } while (w === count); options.push(w); }
            }
            problem.options = options;
            problem.correctIndex = correctIndex;
        }
        problems.push(problem);
    }
    return { problems };
}

function generateNumberDecomposeData(mode?: string, extra?: any) {
    const decomposeMode = mode || 'with-image';
    const maxNumber = extra?.maxNumber || 10;
    const is20 = maxNumber === 20;
    const minWhole = is20 ? 11 : 2;
    const maxWhole = maxNumber;

    const problems: Array<{
        whole: number | null; part1: number | null; part2: number | null;
        imageIndex?: number; imageType?: 'fruits' | 'twelve-animals';
    }> = [];
    const usedKeys = new Set<string>();
    const problemCount = decomposeMode === 'with-image' ? 9 : 15;
    let attempts = 0;

    while (problems.length < problemCount && attempts < problemCount * 50) {
        attempts++;
        const whole = Math.floor(Math.random() * (maxWhole - minWhole + 1)) + minWhole;
        const part1 = Math.floor(Math.random() * (whole - 1)) + 1;
        const part2 = whole - part1;

        if (decomposeMode === 'compose') {
            const key = `${Math.min(part1, part2)}:${Math.max(part1, part2)}`;
            if (usedKeys.has(key)) continue;
            usedKeys.add(key);
            problems.push({ whole: null, part1, part2 });
        } else {
            const showPart1 = Math.random() < 0.5;
            const key = `${whole}:${Math.min(part1, part2)}:${Math.max(part1, part2)}:${showPart1}`;
            if (usedKeys.has(key)) continue;
            usedKeys.add(key);

            const problem: any = {
                whole,
                part1: showPart1 ? part1 : null,
                part2: showPart1 ? null : part2,
            };
            if (decomposeMode === 'with-image') {
                const imgType: 'fruits' | 'twelve-animals' = Math.random() < 0.5 ? 'fruits' : 'twelve-animals';
                problem.imageIndex = Math.floor(Math.random() * (imgType === 'fruits' ? 22 : 12)) + 1;
                problem.imageType = imgType;
            }
            problems.push(problem);
        }
    }
    return { problems, mode: decomposeMode };
}

function generateNumberSortData() {
    const availableColors = getNumberColors();
    const groups: Array<{ numbers: Array<{ number: number; color: string; angle: number }> }> = [];

    for (let i = 0; i < 6; i++) {
        const pool = Array.from({ length: 9 }, (_, i) => i + 1);
        const selected: number[] = [];
        for (let j = 0; j < 4; j++) {
            const idx = Math.floor(Math.random() * pool.length);
            selected.push(pool.splice(idx, 1)[0]);
        }
        const shuffled = [...selected];
        for (let j = shuffled.length - 1; j > 0; j--) {
            const k = Math.floor(Math.random() * (j + 1));
            [shuffled[j], shuffled[k]] = [shuffled[k], shuffled[j]];
        }
        groups.push({
            numbers: shuffled.map((num) => ({
                number: num,
                color: NUMBER_COLORS[num as keyof typeof NUMBER_COLORS] || availableColors[Math.floor(Math.random() * availableColors.length)],
                angle: ((Math.random() - 0.5) * 60 * Math.PI) / 180,
            })),
        });
    }
    return { groups };
}

function generateNumberObjectMatchData() {
    const fruitsIndices = Array.from({ length: 22 }, (_, i) => i + 1);
    const animalsIndices = Array.from({ length: 12 }, (_, i) => i + 1);
    const allImages = [
        ...fruitsIndices.map((idx) => ({ imageIndex: idx, folder: 'fruits' as const })),
        ...animalsIndices.map((idx) => ({ imageIndex: idx, folder: 'twelve-animals' as const })),
    ];
    const selectedImages = [...allImages].sort(() => Math.random() - 0.5).slice(0, 4);

    const gridImages = Array.from({ length: 20 }, () => {
        const img = selectedImages[Math.floor(Math.random() * selectedImages.length)];
        return { ...img, offsetX: (Math.random() - 0.5) * 30, offsetY: (Math.random() - 0.5) * 30 };
    });

    const bottomImages = [...selectedImages];
    const countMap = new Map<string, number>();
    gridImages.forEach((it) => {
        const key = `${it.folder}-${it.imageIndex}`;
        countMap.set(key, (countMap.get(key) || 0) + 1);
    });
    const imageCounts = selectedImages.map((img) => countMap.get(`${img.folder}-${img.imageIndex}`) || 0);
    const bottomNumbers = [...imageCounts].sort(() => Math.random() - 0.5);

    return { gridImages, bottomImages, bottomNumbers };
}

function generateMakeTenData() {
    const problems: Array<{ left: number; right: number; result: number }> = [];
    const used = new Set<string>();
    let attempts = 0;

    while (problems.length < 9 && attempts < 1000) {
        attempts++;
        const bigFirst = Math.random() < 0.5;
        let left: number, right: number;

        if (bigFirst) {
            left = Math.floor(Math.random() * 4) + 6;
            const minR = Math.max(1, 11 - left);
            const maxR = Math.min(left - 1, 20 - left);
            if (maxR < minR) continue;
            right = Math.floor(Math.random() * (maxR - minR + 1)) + minR;
        } else {
            right = Math.floor(Math.random() * 4) + 6;
            const minL = Math.max(1, 11 - right);
            const maxL = Math.min(right - 1, 20 - right);
            if (maxL < minL) continue;
            left = Math.floor(Math.random() * (maxL - minL + 1)) + minL;
        }

        const key = `${left},${right}`;
        if (used.has(key)) continue;
        used.add(key);
        problems.push({ left, right, result: left + right });
    }
    return { problems };
}

function generateBreakTenData() {
    const problems: Array<{ minuend: number; subtrahend: number; result: number }> = [];
    const used = new Set<string>();
    let attempts = 0;

    while (problems.length < 9 && attempts < 1000) {
        attempts++;
        const minuend = Math.floor(Math.random() * 10) + 11;
        const subtrahend = Math.floor(Math.random() * 9) + 1;
        if (minuend <= subtrahend) continue;
        const key = `${minuend},${subtrahend}`;
        if (used.has(key)) continue;
        used.add(key);
        problems.push({ minuend, subtrahend, result: minuend - subtrahend });
    }
    return { problems };
}

function generateFlatTenData() {
    const allValid: Array<{ minuend: number; subtrahend: number; result: number }> = [];
    for (let m = 11; m < 20; m++) {
        const ones = m % 10;
        for (let s = 1; s <= 10; s++) {
            if (s > ones && m > s) allValid.push({ minuend: m, subtrahend: s, result: m - s });
        }
    }
    const shuffled = [...allValid];
    for (let i = shuffled.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
    }
    return { problems: shuffled.slice(0, Math.min(9, shuffled.length)) };
}

function generateBorrowTenData(mode?: string) {
    let maxMinuend = 50;
    if (mode === 'within-30') maxMinuend = 30;
    else if (mode === 'within-100') maxMinuend = 100;

    const byMinuend = new Map<number, Array<{ minuend: number; subtrahend: number; result: number }>>();
    for (let m = 20; m <= maxMinuend; m++) {
        const ones = m % 10;
        for (let s = 1; s <= 10; s++) {
            if (ones < s && m > s) {
                if (!byMinuend.has(m)) byMinuend.set(m, []);
                byMinuend.get(m)!.push({ minuend: m, subtrahend: s, result: m - s });
            }
        }
    }

    const minuends = Array.from(byMinuend.keys());
    for (let i = minuends.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [minuends[i], minuends[j]] = [minuends[j], minuends[i]];
    }

    const problems: Array<{ minuend: number; subtrahend: number; result: number }> = [];
    const target = 9;

    if (minuends.length >= target) {
        for (let i = 0; i < target; i++) {
            const arr = byMinuend.get(minuends[i])!;
            problems.push(arr[Math.floor(Math.random() * arr.length)]);
        }
    } else {
        const per = Math.floor(target / minuends.length);
        const rem = target % minuends.length;
        for (let i = 0; i < minuends.length; i++) {
            const arr = [...byMinuend.get(minuends[i])!];
            for (let k = arr.length - 1; k > 0; k--) { const j = Math.floor(Math.random() * (k + 1)); [arr[k], arr[j]] = [arr[j], arr[k]]; }
            const count = per + (i < rem ? 1 : 0);
            for (let j = 0; j < Math.min(count, arr.length); j++) problems.push(arr[j]);
        }
    }

    for (let i = problems.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [problems[i], problems[j]] = [problems[j], problems[i]];
    }
    return { problems };
}

function generateOneDigitAdditionData() {
    const problems: Array<{ left: number; right: number; result: number }> = [];
    const used = new Set<string>();
    let attempts = 0;

    while (problems.length < 6 && attempts < 1000) {
        attempts++;
        const left = Math.floor(Math.random() * 9) + 1;
        const right = Math.floor(Math.random() * (10 - left)) + 1;
        const key = `${left},${right}`;
        if (used.has(key)) continue;
        used.add(key);
        problems.push({ left, right, result: left + right });
    }
    return { problems };
}

function generateCalculationPracticeData(mode?: string, extra?: any) {
    const opType = extra?.operationType || 'addition';
    let maxValue = 10;
    if (mode === 'within-20') maxValue = 20;
    else if (mode === 'within-50') maxValue = 50;
    else if (mode === 'within-100') maxValue = 100;

    const problems: Array<{ left: number; operator: '+' | '-'; right: number; result: number }> = [];
    const used = new Set<string>();
    let attempts = 0;

    while (problems.length < 33 && attempts < 2000) {
        attempts++;
        let left: number, right: number, operator: '+' | '-', result: number;

        const doAdd = opType === 'addition' ? true : opType === 'subtraction' ? false : Math.random() < 0.5;
        if (doAdd) {
            left = Math.floor(Math.random() * (maxValue - 1)) + 1;
            right = Math.floor(Math.random() * (maxValue - left)) + 1;
            operator = '+'; result = left + right;
        } else {
            left = Math.floor(Math.random() * maxValue) + 1;
            right = Math.floor(Math.random() * left) + 1;
            operator = '-'; result = left - right;
        }

        const key = `${left},${operator},${right}`;
        if (used.has(key)) continue;
        used.add(key);
        problems.push({ left, operator, right, result });
    }
    return { problems };
}

function generateMultiplicationTableData() {
    return {};
}

// ─── Registry ───

export const MATH_TYPE_CONFIGS: MathTypeConfig[] = [
    {
        id: 'number-find',
        title: '看数字，涂一涂',
        subTitle: '找一找下面相同的数字，涂上颜色',
        icon: '🔍',
        hasNumberGrid: true,
        createDrawService: (canvas, ctx, opts) => new NumberFindDraw(canvas, ctx, opts),
        generateData: generateNumberFindData,
    },
    {
        id: 'counting-matching',
        title: '数一数，连一连',
        subTitle: '通过连线配对数字和对应的数量图形',
        icon: '🔗',
        actionsTitle: '选择图片',
        actions: [
            { value: 'twelve-animals', label: '十二生肖' },
            { value: 'fruits', label: '水果' },
        ],
        defaultMode: 'twelve-animals',
        createDrawService: (canvas, ctx, opts) => new CountMatchDraw(canvas, ctx, opts),
        generateData: generateCountMatchData,
    },
    {
        id: 'number-coloring',
        title: '按数字涂颜色',
        subTitle: '按数字给相应的圆圈涂上颜色',
        icon: '🎨',
        actionsTitle: '选择样式',
        actions: [
            { value: 'caterpillar', label: '毛毛虫' },
            { value: 'circle', label: '圆圈' },
        ],
        defaultMode: 'caterpillar',
        createDrawService: (canvas, ctx, opts) => new NumberColorDraw(canvas, ctx, opts),
        generateData: generateNumberColorData,
    },
    {
        id: 'addition',
        title: '图形加减法',
        subTitle: '通过图形化方式学习加减法运算',
        icon: '➕',
        actionsTitle: '选择类型',
        actions: [
            { value: 'addition-5', label: '5以内加法' },
            { value: 'addition-10', label: '10以内加法' },
            { value: 'subtraction-10', label: '10以内减法' },
            { value: 'addition-subtraction-10', label: '10以内加减法' },
        ],
        defaultMode: 'addition-5',
        createDrawService: (canvas, ctx, opts) => new AdditionDraw(canvas, ctx, opts),
        generateData: generateAdditionData,
    },
    {
        id: 'missing-number',
        title: '填缺少的数字',
        subTitle: '在数字序列中找出并填写缺失的数字',
        icon: '❓',
        actionsTitle: '选择范围',
        actions: [
            { value: '10', label: '10以内' },
            { value: '20', label: '20以内' },
            { value: '40', label: '40以内' },
            { value: '50', label: '50以内' },
            { value: '80', label: '80以内' },
            { value: '100', label: '100以内' },
            { value: '120', label: '120以内' },
        ],
        defaultMode: '10',
        createDrawService: (canvas, ctx, opts) => new MissingNumberDraw(canvas, ctx, opts),
        generateData: generateMissingNumberData,
    },
    {
        id: 'compare',
        title: '数一数，比大小',
        subTitle: '数一数，比较数量，在⭕️中填入＞、＜、＝',
        icon: '⚖️',
        createDrawService: (canvas, ctx, opts) => new CompareDraw(canvas, ctx, opts),
        generateData: generateCompareData,
    },
    {
        id: 'counting-select',
        title: '数一数，选一选',
        subTitle: '数出物品数量，从多个选项中选择正确答案',
        icon: '🎯',
        createDrawService: (canvas, ctx, opts) => new CountingSelectDraw(canvas, ctx, opts),
        generateData: generateCountingSelectData,
    },
    {
        id: 'number-decompose',
        title: '10以内分与合',
        subTitle: '学习数的分解与组合',
        icon: '🌳',
        actionsTitle: '选择模式',
        actions: [
            { value: 'with-image', label: '有图片模式' },
            { value: 'decompose', label: '分模式' },
            { value: 'compose', label: '组合模式' },
        ],
        defaultMode: 'with-image',
        createDrawService: (canvas, ctx, opts) => new NumberDecomposeDraw(canvas, ctx, opts),
        generateData: (mode) => generateNumberDecomposeData(mode, { maxNumber: 10 }),
    },
    {
        id: 'number-decompose-20',
        title: '20以内分与合',
        subTitle: '学习20以内数的分解与组合',
        icon: '🌲',
        actionsTitle: '选择模式',
        actions: [
            { value: 'decompose', label: '20以内的分解' },
            { value: 'compose', label: '20以内的组合' },
        ],
        defaultMode: 'decompose',
        createDrawService: (canvas, ctx, opts) => new NumberDecomposeDraw(canvas, ctx, opts),
        generateData: (mode) => generateNumberDecomposeData(mode, { maxNumber: 20 }),
    },
    {
        id: 'number-sort',
        title: '数字排序',
        subTitle: '数字排序，写出正确顺序',
        icon: '🔢',
        createDrawService: (canvas, ctx, opts) => new NumberSortDraw(canvas, ctx, opts),
        generateData: generateNumberSortData,
    },
    {
        id: 'number-object-match',
        title: '数物对应',
        subTitle: '数一数图片数量并对应数字',
        icon: '🧮',
        actionsTitle: '选择模式',
        actions: [
            { value: 'match', label: '连线' },
            { value: 'fill', label: '填写' },
        ],
        defaultMode: 'match',
        createDrawService: (canvas, ctx, opts) => new NumberObjectMatchDraw(canvas, ctx, opts),
        generateData: generateNumberObjectMatchData,
    },
    {
        id: 'make-ten',
        title: '凑十法练习',
        subTitle: '通过凑十法学习20以内进位加法',
        icon: '🔟',
        createDrawService: (canvas, ctx, opts) => new MakeTenDraw(canvas, ctx, opts),
        generateData: generateMakeTenData,
    },
    {
        id: 'break-ten',
        title: '破十法练习',
        subTitle: '通过破十法学习20以内退位减法',
        icon: '💥',
        createDrawService: (canvas, ctx, opts) => new BreakTenDraw(canvas, ctx, opts),
        generateData: generateBreakTenData,
    },
    {
        id: 'flat-ten',
        title: '平十法练习',
        subTitle: '通过平十法学习退位减法',
        icon: '📐',
        createDrawService: (canvas, ctx, opts) => new FlatTenDraw(canvas, ctx, opts),
        generateData: generateFlatTenData,
    },
    {
        id: 'borrow-ten',
        title: '借十法练习',
        subTitle: '拆大数，借出10，减小数，加剩数',
        icon: '🏦',
        actionsTitle: '选择范围',
        actions: [
            { value: 'within-30', label: '30以内' },
            { value: 'within-50', label: '50以内' },
            { value: 'within-100', label: '100以内' },
        ],
        defaultMode: 'within-50',
        createDrawService: (canvas, ctx, opts) => new BreakTenDraw(canvas, ctx, { ...opts, mnemonic: '拆大数，借出10，减小数，加剩数' }),
        generateData: generateBorrowTenData,
    },
    {
        id: 'one-digit-addition',
        title: '一位数加法',
        subTitle: '通过圆点学习一位数加法运算',
        icon: '⚫',
        createDrawService: (canvas, ctx, opts) => new OneDigitAdditionDraw(canvas, ctx, opts),
        generateData: generateOneDigitAdditionData,
    },
    {
        id: 'practice-addition',
        title: '加法口算',
        subTitle: '加法计算练习题',
        icon: '📝',
        actionsTitle: '选择范围',
        actions: [
            { value: 'within-10', label: '10以内' },
            { value: 'within-20', label: '20以内' },
            { value: 'within-50', label: '50以内' },
            { value: 'within-100', label: '100以内' },
        ],
        defaultMode: 'within-10',
        createDrawService: (canvas, ctx, opts) => new CalculationPracticeDraw(canvas, ctx, opts),
        generateData: (mode) => generateCalculationPracticeData(mode, { operationType: 'addition' }),
    },
    {
        id: 'practice-subtraction',
        title: '减法口算',
        subTitle: '减法计算练习题',
        icon: '📝',
        actionsTitle: '选择范围',
        actions: [
            { value: 'within-10', label: '10以内' },
            { value: 'within-20', label: '20以内' },
            { value: 'within-50', label: '50以内' },
            { value: 'within-100', label: '100以内' },
        ],
        defaultMode: 'within-10',
        createDrawService: (canvas, ctx, opts) => new CalculationPracticeDraw(canvas, ctx, opts),
        generateData: (mode) => generateCalculationPracticeData(mode, { operationType: 'subtraction' }),
    },
    {
        id: 'practice-mixed',
        title: '混合口算',
        subTitle: '加减法混合计算练习题',
        icon: '📝',
        actionsTitle: '选择范围',
        actions: [
            { value: 'within-10', label: '10以内' },
            { value: 'within-20', label: '20以内' },
            { value: 'within-50', label: '50以内' },
            { value: 'within-100', label: '100以内' },
        ],
        defaultMode: 'within-10',
        createDrawService: (canvas, ctx, opts) => new CalculationPracticeDraw(canvas, ctx, opts),
        generateData: (mode) => generateCalculationPracticeData(mode, { operationType: 'mixed' }),
    },
    {
        id: 'multiplication-table',
        title: '九九乘法表',
        subTitle: '九九乘法表',
        icon: '✖️',
        createDrawService: (canvas, ctx, opts) => new MultiplicationTableDraw(canvas, ctx, opts),
        generateData: generateMultiplicationTableData,
    },
];

/**
 * 通过路由 ID 查找类型配置
 * 处理别名映射：counting-fill → counting-select, number-object-fill → number-object-match 等
 */
export function findTypeByRouteId(
    routeId: string,
): { typeConfig: MathTypeConfig; mode?: string; extra?: Record<string, any> } | null {
    const direct = MATH_TYPE_CONFIGS.find((t) => t.id === routeId);
    if (direct) return { typeConfig: direct };

    // 别名映射
    const aliases: Record<string, { typeId: string; extra?: Record<string, any> }> = {
        'counting-fill': { typeId: 'counting-select', extra: { functionId: 'counting-fill' } },
        'number-object-fill': { typeId: 'number-object-match', extra: { defaultMode: 'fill' } },
        'number-write': { typeId: 'number-find', extra: { functionId: 'number-write' } },
        'number-find': { typeId: 'number-find' },
        'addition-5': { typeId: 'addition' },
        'addition-10': { typeId: 'addition', extra: { defaultMode: 'addition-10' } },
        'subtraction-10': { typeId: 'addition', extra: { defaultMode: 'subtraction-10' } },
        'addition-subtraction-10': { typeId: 'addition', extra: { defaultMode: 'addition-subtraction-10' } },
    };

    const alias = aliases[routeId];
    if (alias) {
        const cfg = MATH_TYPE_CONFIGS.find((t) => t.id === alias.typeId);
        if (cfg) return { typeConfig: cfg, mode: alias.extra?.defaultMode, extra: alias.extra };
    }

    return { typeConfig: MATH_TYPE_CONFIGS[0] };
}
