import APP from '@/services';
import { getGoodsByCode } from '@/services/bus/goods';
import { getLongTypeLoginID, isLogin } from '@/services/bus/login';
import { getToken } from '@/services/bus/token';
import { funCode } from '@/services/funcode/index';
import { QueryQuoteDayRsp } from '@/services/go/quote/interface';
import { mergeObj } from '@/utils/objHandle';
import { Package40 } from '@/utils/websocket/package';
import Long from 'long';
import { SubscribeInfoType } from '../interface';
import { byteArrayToUInt, subscribeInfosToByteArrary } from './byteUtils';

/**
 * 构建行情订阅请求包
 */
export function buildSubscribePeq(subscribeInfos: SubscribeInfoType[]): Package40 {
    // 如果是登录状态,就走正常行情链路. 否则走游客
    const loginId = isLogin() ? getLongTypeLoginID() : Long.fromNumber(2);
    const token = isLogin() ? getToken() : '2_TOKEN_NEKOT_';
    const content = subscribeInfosToByteArrary(subscribeInfos, token, loginId);
    const reqPackage = new Package40([funCode.MainClassNumber_Quota_SubscriptReq, content], undefined);
    return reqPackage;
}

/**
 * 解析行情订阅请求包
 * @param rspPackage
 */
export function parseSubscribeRsp(rspPackage: any): Promise<string | SubscribeInfoType[]> {
    return new Promise((resolve, reject) => {
        const content = rspPackage.content;
        if (content.length === 0) {
            // 有可能空订阅，也有可能订阅返回数据为空，但其实已经订阅了商品
            // 暂做正常返回 空字符串 处理，如遇到问题继续优化即可
            console.warn('行情订阅请求包返回为空');
            resolve('');
        }
        const count = byteArrayToUInt(content.subarray(0, 4), false);
        if (count > 1000) {
            // 游客模式 刷新成长问题，为了不让页面卡死，暂时处理
            return null;
        }
        switch (count) {
            case -1:
                reject('订阅失败');
            case -2:
                reject('Token校验失败');
            case -3:
                reject('无对应商品信息');
            default:
                break;
        }
        // 判断返回的Count是否有问题
        if (!count || count > (content.length - 4) / 66) {
            reject('行情订阅返回数据不正确');
        }
        const result: SubscribeInfoType[] = [];
        let position = 4;
        for (let i = 0; i < count; i++) {
            const dataArray = content.subarray(position, position + 66);
            const subState = dataArray[0];
            // FIXME: 目前行情接入服务不能正确返回交易所代码
            const exchangeCode = dataArray[2];
            const goodsCode = String.fromCharCode(...dataArray.subarray(2, dataArray.length)).trim();
            result.push({ subState, goodsCode, exchangeCode });
            position += 66;
        }
        resolve(result);
    });
}

/**
 * 解析行情推送报文
 * @param {Array} quotationData	行情信息
 * @param {Boolean} isPushQuote	实时行情推送为true；盘面为false
 *
 */
export function parseReceivePush(quotationData: any) {
    // 目前发现可能会传入空数组
    if (!quotationData.length) {
        return;
    }

    // 分解行正则
    const regRow = /10\s.*?11/g;
    // 分解单行 key 正则
    const regKey = /01\s.*?02/g;
    // 分解单行 value 正则
    const regValue = /02\s.*?01|02\s.*?11/g;

    // 记录已经更新盘面的商品信息数组
    // 0x10 ... 0x01 key 0x02 value 0x01 key 0x02 value ... 0x11
    const hexString = Array.prototype.map.call(quotationData, (x) => ('00' + x.toString(16)).slice(-2)).join(' ');
    // let hexString = 'FF 10 01 55 02 45 46 47 48 01 66 02 48 47 46 45 11 10 01 77 02 AA BB CC DD 11 00';

    // 获取单行行情
    const rows = hexString.match(regRow);
    if (rows === null) {
        return;
    }
    for (const low of rows) {
        // 获取 key value 表列
        const keys: any = low.match(regKey);
        const values: any = low.match(regValue);

        const goodsQuoteTik: any = {};
        for (let i = 0; i < keys.length; i++) {
            const key = parseInt(keys[i].substring(3, 5), 16);

            const tmpValue = values[i];
            const value = new Uint8Array(
                tmpValue
                    .substring(3, tmpValue.length - 3)
                    .split(' ')
                    .map((byte: any) => parseInt(byte, 16))
            );

            // 缓存值
            setQuoteTikFieldByByte(goodsQuoteTik, key, value);
        }
        const quoteDayInfo = APP.getRef('quoteDayInfo');
        const itemQuote = quoteDayInfo.value.find((el: QueryQuoteDayRsp) => el.goodscode === goodsQuoteTik.goodscode);
        if (itemQuote) {
            const goods = getGoodsByCode(itemQuote.goodscode);
            if (goods) {
                // 处理报价小数为
                const decimalplace = goods.decimalplace
                const num = Math.pow(10, decimalplace)
                const fn = (value: number) => +(value / num).toFixed(decimalplace)
                goodsQuoteTik.decimalplace = decimalplace
                goodsQuoteTik.last = goodsQuoteTik.last ? fn(goodsQuoteTik.last) : '--'
                goodsQuoteTik.presettle = goodsQuoteTik.presettle ? (fn(goodsQuoteTik.presettle)) : '--'
                goodsQuoteTik.ask = goodsQuoteTik.ask ? (fn(goodsQuoteTik.ask)) : '--'
                goodsQuoteTik.ask2 = goodsQuoteTik.ask2 ? (fn(goodsQuoteTik.ask2)) : '--'
                goodsQuoteTik.ask3 = goodsQuoteTik.ask3 ? (fn(goodsQuoteTik.ask3)) : '--'
                goodsQuoteTik.ask4 = goodsQuoteTik.ask4 ? (fn(goodsQuoteTik.ask4)) : '--'
                goodsQuoteTik.ask5 = goodsQuoteTik.ask5 ? (fn(goodsQuoteTik.ask5)) : '--'
                goodsQuoteTik.ask6 = goodsQuoteTik.ask6 ? (fn(goodsQuoteTik.ask6)) : '--'
                goodsQuoteTik.ask7 = goodsQuoteTik.ask7 ? (fn(goodsQuoteTik.ask7)) : '--'
                goodsQuoteTik.ask8 = goodsQuoteTik.ask8 ? (fn(goodsQuoteTik.ask8)) : '--'
                goodsQuoteTik.ask9 = goodsQuoteTik.ask9 ? (fn(goodsQuoteTik.ask9)) : '--'
                goodsQuoteTik.ask10 = goodsQuoteTik.ask10 ? (fn(goodsQuoteTik.ask10)) : '--'
                goodsQuoteTik.bid = goodsQuoteTik.bid ? (fn(goodsQuoteTik.bid)) : '--'
                goodsQuoteTik.bid2 = goodsQuoteTik.bid2 ? (fn(goodsQuoteTik.bid2)) : '--'
                goodsQuoteTik.bid3 = goodsQuoteTik.bid3 ? (fn(goodsQuoteTik.bid3)) : '--'
                goodsQuoteTik.bid4 = goodsQuoteTik.bid4 ? (fn(goodsQuoteTik.bid4)) : '--'
                goodsQuoteTik.bid5 = goodsQuoteTik.bid5 ? (fn(goodsQuoteTik.bid5)) : '--'
                goodsQuoteTik.bid6 = goodsQuoteTik.bid6 ? (fn(goodsQuoteTik.bid6)) : '--'
                goodsQuoteTik.bid7 = goodsQuoteTik.bid7 ? (fn(goodsQuoteTik.bid7)) : '--'
                goodsQuoteTik.bid8 = goodsQuoteTik.bid8 ? (fn(goodsQuoteTik.bid8)) : '--'
                goodsQuoteTik.bid9 = goodsQuoteTik.bid9 ? (fn(goodsQuoteTik.bid9)) : '--'
                goodsQuoteTik.bid10 = goodsQuoteTik.bid10 ? (fn(goodsQuoteTik.bid10)) : '--'
                goodsQuoteTik.averageprice = goodsQuoteTik.averageprice ? (fn(goodsQuoteTik.averageprice)) : '--'
                goodsQuoteTik.grepmarketprice = goodsQuoteTik.grepmarketprice ? (fn(goodsQuoteTik.grepmarketprice)) : '--'
                goodsQuoteTik.highest = goodsQuoteTik.highest ? (fn(goodsQuoteTik.highest)) : '--'
                goodsQuoteTik.iep = goodsQuoteTik.iep ? (fn(goodsQuoteTik.iep)) : '--'
                goodsQuoteTik.limitdown = goodsQuoteTik.limitdown ? (fn(goodsQuoteTik.limitdown)) : '--'
                goodsQuoteTik.limitup = goodsQuoteTik.limitup ? (fn(goodsQuoteTik.limitup)) : '--'
                goodsQuoteTik.lowest = goodsQuoteTik.lowest ? (fn(goodsQuoteTik.lowest)) : '--'
                goodsQuoteTik.opened = goodsQuoteTik.opened ? (fn(goodsQuoteTik.opened)) : '--'
                goodsQuoteTik.preclose = goodsQuoteTik.preclose ? (fn(goodsQuoteTik.preclose)) : '--'
                goodsQuoteTik.settle = goodsQuoteTik.settle ? (fn(goodsQuoteTik.settle)) : '--'
                goodsQuoteTik.strikeprice = goodsQuoteTik.strikeprice ? (fn(goodsQuoteTik.strikeprice)) : '--'

                // !goodsQuoteTik.bidvolume && (goodsQuoteTik.bidvolume = '--')
                // !goodsQuoteTik.askvolume && (goodsQuoteTik.askvolume = '--')
                !goodsQuoteTik.lastvolume && (goodsQuoteTik.lastvolume = '--')
                !goodsQuoteTik.holdvolume && (goodsQuoteTik.holdvolume = '--')
                !goodsQuoteTik.holdincrement && (goodsQuoteTik.holdincrement = '--')
                // !goodsQuoteTik.totalturnover && (goodsQuoteTik.totalturnover = '--')

            } else {
                console.warn(`行情推送的商品goods:${itemQuote.goodscode}在商品列表里不存在`)
            }

            // 注意：此处已 go 服务查询出来的盘面数据为基准，查询盘面 先修改成go 服务，第一次进入项目时候回查询一次所有盘面
            // 之前是 通过 websocket 查询的，故 可能存在字段发生变化问题，如遇到，则进行优化处理
            mergeObj(itemQuote, goodsQuoteTik);
        } else {
            // 此处 待优化（存在字段变化问题）
            quoteDayInfo.push(itemQuote);
        }
    }
}

/**
 * 分解缓存行情字段的方法
 *   goodsQuoteTik
 *   keyItem
 *   valueItem
 */
function setQuoteTikFieldByByte(goodsQuoteTik: any, keyItem: any, valueItem: any) {
    const strValue = String.fromCharCode(...valueItem);
    switch (keyItem) {
        case 0x56:
            goodsQuoteTik.exchangecode = strValue;
            break;
        case 0x21:
            goodsQuoteTik.goodscode = strValue;
            break;
        case 0x24:
            goodsQuoteTik.last = Number(strValue);
            break;
        case 0x5b:
            goodsQuoteTik.holdvolume = Number(strValue);
            break;
        case 0x25:
            goodsQuoteTik.lastvolume = Number(strValue);
            break;
        case 0x3c:
            goodsQuoteTik.preholdvolume = Number(strValue);
            break;
        case 0x32:
            goodsQuoteTik.presettle = Number(strValue);
            break;
        case 0x33:
            goodsQuoteTik.settle = Number(strValue);
            break;
        case 0x29:
            goodsQuoteTik.totalturnover = Number(strValue);
            break;
        case 0x28:
            goodsQuoteTik.totalvolume = Number(strValue);
            break;
        case 0x35:
            goodsQuoteTik.limithigh = Number(strValue);
            break;
        case 0x36:
            goodsQuoteTik.limitlow = Number(strValue);
            break;
        case 'L'.charCodeAt(0):
            goodsQuoteTik.ask = Number(strValue);
            break;
        case 'M'.charCodeAt(0):
            goodsQuoteTik.ask2 = Number(strValue);
            break;
        case 'N'.charCodeAt(0):
            goodsQuoteTik.ask3 = Number(strValue);
            break;
        case 'O'.charCodeAt(0):
            goodsQuoteTik.ask4 = Number(strValue);
            break;
        case 'P'.charCodeAt(0):
            goodsQuoteTik.ask5 = Number(strValue);
            break;
        case 'Q'.charCodeAt(0):
            goodsQuoteTik.askvolume = Number(strValue);
            break;
        case 'R'.charCodeAt(0):
            goodsQuoteTik.askvolume2 = Number(strValue);
            break;
        case 'S'.charCodeAt(0):
            goodsQuoteTik.askvolume3 = Number(strValue);
            break;
        case 'T'.charCodeAt(0):
            goodsQuoteTik.askvolume4 = Number(strValue);
            break;
        case 'U'.charCodeAt(0):
            goodsQuoteTik.askvolume5 = Number(strValue);
            break;
        case 'B'.charCodeAt(0):
            goodsQuoteTik.bid = Number(strValue);
            break;
        case 'C'.charCodeAt(0):
            goodsQuoteTik.bid2 = Number(strValue);
            break;
        case 'D'.charCodeAt(0):
            goodsQuoteTik.bid3 = Number(strValue);
            break;
        case 'E'.charCodeAt(0):
            goodsQuoteTik.bid4 = Number(strValue);
            break;
        case 'F'.charCodeAt(0):
            goodsQuoteTik.bid5 = Number(strValue);
            break;
        case 'G'.charCodeAt(0):
            goodsQuoteTik.bidvolume = Number(strValue);
            break;
        case 'H'.charCodeAt(0):
            goodsQuoteTik.bidvolume2 = Number(strValue);
            break;
        case 'I'.charCodeAt(0):
            goodsQuoteTik.bidvolume3 = Number(strValue);
            break;
        case 'J'.charCodeAt(0):
            goodsQuoteTik.bidvolume4 = Number(strValue);
            break;
        case 'K'.charCodeAt(0):
            goodsQuoteTik.bidvolume5 = Number(strValue);
            break;
        case ','.charCodeAt(0):
            goodsQuoteTik.highest = Number(strValue);
            break;
        case '-'.charCodeAt(0):
            goodsQuoteTik.lowest = Number(strValue);
            break;
        case '@'.charCodeAt(0):
            goodsQuoteTik.date = strValue;
            break;
        case 'A'.charCodeAt(0):
            goodsQuoteTik.time = strValue;
            break;
        case '+'.charCodeAt(0):
            goodsQuoteTik.preclose = Number(strValue);
            break;
        case '.'.charCodeAt(0):
            goodsQuoteTik.opened = Number(strValue);
            break;
        case 0x5c:
            goodsQuoteTik.exerciseprice = Number(strValue);
            break;
        case 0x7a:
            goodsQuoteTik.inventory = Number(strValue);
            break;
        case 0x7c:
            goodsQuoteTik.exchangedate = Number(strValue);
            break;
        case 0x70:
            goodsQuoteTik.strbidorder = strValue;
            break;
        case 0x71:
            goodsQuoteTik.strbidorder2 = strValue;
            break;
        case 0x72:
            goodsQuoteTik.strbidorder3 = strValue;
            break;
        case 0x73:
            goodsQuoteTik.strbidorder4 = strValue;
            break;
        case 0x74:
            goodsQuoteTik.strbidorder5 = strValue;
            break;
        case 0x75:
            goodsQuoteTik.straskorder = strValue;
            break;
        case 0x76:
            goodsQuoteTik.straskorder2 = strValue;
            break;
        case 0x77:
            goodsQuoteTik.straskorder3 = strValue;
            break;
        case 0x78:
            goodsQuoteTik.straskorder4 = strValue;
            break;
        case 0x79:
            goodsQuoteTik.straskorder5 = strValue;
            break;
        case 0x7d:
            goodsQuoteTik.putoptionpremiums = strValue;
            break;
        case 0x7e:
            goodsQuoteTik.putoptionpremiums2 = strValue;
            break;
        case 0x80:
            goodsQuoteTik.putoptionpremiums3 = strValue;
            break;
        case 0x81:
            goodsQuoteTik.putoptionpremiums4 = strValue;
            break;
        case 0x82:
            goodsQuoteTik.putoptionpremiums5 = strValue;
            break;
        case 0x83:
            goodsQuoteTik.calloptionpremiums = strValue;
            break;
        case 0x84:
            goodsQuoteTik.calloptionpremiums2 = strValue;
            break;
        case 0x85:
            goodsQuoteTik.calloptionpremiums3 = strValue;
            break;
        case 0x86:
            goodsQuoteTik.calloptionpremiums4 = strValue;
            break;
        case 0x87:
            goodsQuoteTik.calloptionpremiums5 = strValue;
            break;
        default:
            break;
    }
}
