import { reactive } from 'vue'
import { EchartsDataset, Candlestick, MACD } from './interface'

export function useDataset() {
    const dataset = reactive<EchartsDataset>({
        invalid: [],
        candlestick: {
            dimensions: ['date', 'open', 'close', 'lowest', 'highest', 'ma5', 'ma10', 'ma15'],
            source: [],
        },
        macd: {
            dimensions: ['date', 'macd', 'dif', 'dea'],
            source: [],
        },
        vol: {
            dimensions: ['date', 'vol'],
            source: [],
        },
        kdj: {
            dimensions: ['date', 'k', 'd', 'j'],
            source: [],
        },
        cci: {
            dimensions: ['date', 'cci'],
            source: [],
        }
    })

    // 清空数据
    const clearData = () => {
        dataset.invalid = [];
        dataset.candlestick.source = [];
        dataset.macd.source = [];
        dataset.vol.source = [];
        dataset.kdj.source = [];
        dataset.cci.source = [];
    }

    // 处理行情数据
    const handleData = (rawData: Ermcp.QueryHistoryDatasRsp[], onReady?: () => void) => {
        for (let i = 0; i < rawData.length; i++) {
            const { o, c, h, l, ts: date, f, tv } = rawData[i];
            if (f) dataset.invalid.push(i); // 添加补充数据的索引位置

            dataset.candlestick.source.push({
                date,
                open: o,
                close: c,
                lowest: l,
                highest: h,
                ma5: '-',
                ma10: '-',
                ma15: '-',
            })

            dataset.macd.source.push({
                date,
                ema12: 0,
                ema26: 0,
                dif: 0,
                dea: 0,
                macd: 0,
            })

            dataset.vol.source.push({
                date,
                vol: tv,
            })

            dataset.kdj.source.push({
                date,
                k: '-',
                d: '-',
                j: '-'
            })

            dataset.cci.source.push({
                date,
                cci: '-',
            })
        }
        // 计算各种指标
        calcIndicator();
        onReady && onReady();
    }

    // 计算MA
    const calcMA = (count: 5 | 10 | 15, startIndex = 0) => {
        const key: keyof Candlestick = count === 5 ? 'ma5' : count === 10 ? 'ma10' : 'ma15';
        const candlestickSource = dataset.candlestick.source;

        for (let i = startIndex; i < candlestickSource.length; i++) {
            // 判断是否补充数据
            if (dataset.invalid.includes(i)) {
                const value = i > 0 ? candlestickSource[i - 1][key] : '-'; // 如果存在，取上一条记录的MA值
                candlestickSource[i][key] = value;
            } else {
                let n = 0;
                const tmpList: Candlestick[] = [];

                for (let j = i; j >= 0; j--) {
                    if (dataset.invalid.includes(j)) continue; // 如果是补充数据，跳过本次循环
                    if (n === count) break; // 如果 n 等于计数，结束循环
                    tmpList.push(candlestickSource[j]);
                    n++;
                }

                if (n === count) {
                    // 计算总价(收盘价总和)
                    const total = tmpList.reduce((res, e) => res + e.close, 0);
                    // 计算均价
                    candlestickSource[i][key] = (total / count).toFixed(2);
                } else {
                    candlestickSource[i][key] = '-';
                }
            }
        }
    }

    // 计算EMA
    const calcEMA = (count: 12 | 26, startIndex = 0) => {
        const key: keyof MACD = count === 12 ? 'ema12' : 'ema26';
        const macdSource = dataset.macd.source;
        const candlestickSource = dataset.candlestick.source;
        const a = 2 / (count + 1); // 平滑系数

        for (let i = startIndex; i < candlestickSource.length; i++) {
            const close = candlestickSource[i].close; // 收盘价

            if (i === 0) {
                macdSource[i][key] = close; // 初始EMA取收盘价
            } else {
                const prevEMA = macdSource[i - 1][key]; // 昨日EMA
                const value = a * close + (1 - a) * Number(prevEMA);

                macdSource[i][key] = value;
            }
        }
    }

    // 计算MACD
    const calcMACD = (startIndex = 0) => {
        // 先计算EMA
        calcEMA(12, startIndex); // EMA(12) = 2 ÷ 13 * 今日收盘价(12) + 11 ÷ 13 * 昨日EMA(12)
        calcEMA(26, startIndex);

        const macdSource = dataset.macd.source;

        for (let i = startIndex; i < macdSource.length; i++) {
            const { ema12, ema26 } = macdSource[i];
            const prevDEA = i > 0 ? macdSource[i - 1].dea : 0; // 昨日DEA

            const dif = ema12 - ema26; // DIF = 今日EMA(12) - 今日EMA(26)
            const dea = prevDEA * 8 / 10 + dif * 2 / 10; // DEA = 昨日DEA × 8 ÷ 10 + 今日DIF × 2 ÷ 10
            const macd = (dif - dea) * 2; // MACD = (DIFF - DEA) × 2

            macdSource[i].dif = Number(dif.toFixed(2));
            macdSource[i].dea = Number(dea.toFixed(2));
            macdSource[i].macd = Number(macd.toFixed(2));
        }
    }

    // 计算KDJ
    const calcKDJ = (startIndex = 0) => {
        const count = 9; // 以9日周期计算
        const candlestickSource = dataset.candlestick.source;
        const kdjSource = dataset.kdj.source;

        for (let i = startIndex; i < candlestickSource.length; i++) {
            let n = 0;
            const tmpList: Candlestick[] = [];

            for (let j = i; j >= 0; j--) {
                if (n === count) break; // 如果 n 等于计数，结束循环
                tmpList.push(candlestickSource[j]);
                n++;
            }

            if (n === count) {
                const close = candlestickSource[i].close, // 收盘价
                    n9 = tmpList.map((item) => item.close),
                    h9 = Math.max(...n9), // 9天内最高价
                    l9 = Math.min(...n9); // 9天内最低价

                const rsv = (close - l9) / (h9 - l9) * 100, // RSV = (Ct-L9) ÷ (H9-L9) * 100
                    prevK = Number(kdjSource[i - 1].k), // 昨日K值
                    prevD = Number(kdjSource[i - 1].d); // 昨日D值

                const kValue = isNaN(prevK) ? 50 : prevK; // 若无昨日K值，则可用50来代替
                const dValue = isNaN(prevD) ? 50 : prevD; // 若无昨日D值，则可用50来代替

                const k = (2 / 3) * kValue + (1 / 3) * rsv, // K = 2 ÷ 3 × 昨日K值 ＋ 1 ÷ 3 × RSV
                    d = (2 / 3) * dValue + (1 / 3) * k, // D = 2 ÷ 3 × 昨日D值 ＋ 1 ÷ 3 × K值
                    j = 3 * k - 2 * d; // J = 3 * K值 - 2 * D值

                kdjSource[i].k = k.toFixed(2);
                kdjSource[i].d = d.toFixed(2);
                kdjSource[i].j = j.toFixed(2);
            }
        }
    }

    // 计算CCI
    const calcCCI = (startIndex = 0) => {
        const count = 14; // 以14日周期计算
        const candlestickSource = dataset.candlestick.source;
        const cciSource = dataset.cci.source;

        for (let i = startIndex; i < candlestickSource.length; i++) {
            let n = 0;
            const tmpList: Candlestick[] = [];

            for (let j = i; j >= 0; j--) {
                if (n === count) break; // 如果 n 等于计数，结束循环
                tmpList.push(candlestickSource[j]);
                n++;
            }

            if (n === count) {
                const calcTP = (item: Candlestick) => (item.highest + item.lowest + item.close) / 3; // TP = (最高价 + 最低价 + 收盘价) ÷ 3
                const tp = calcTP(candlestickSource[i]),
                    ma = tmpList.reduce((res, e) => res + calcTP(e), 0) / count, // MA = 近N日TP的累计之和 ÷ N
                    md = tmpList.reduce((res, e) => res + Math.abs(calcTP(e) - ma), 0) / count; // MD = 近N日TP的绝对值的累计之和 ÷ N

                const cci = (tp - ma) / (md * 0.015);
                cciSource[i].cci = cci.toFixed(2);
            }
        }
    }

    // 计算各项指标
    const calcIndicator = (startIndex = 0) => {
        calcMA(5, startIndex);
        calcMA(10, startIndex);
        calcMA(15, startIndex);
        calcMACD(startIndex);
        calcKDJ(startIndex);
        calcCCI(startIndex);
    }

    return {
        dataset,
        handleData,
        clearData,
        calcIndicator,
    }
}