import WebSocketService from './WebSocket';
import { IConfig, IDeviceConfig, IDeviceResponse, IQueryConfig, IResponse, IUpgradeConfig, IWsParams } from '../ts/interfaces';
import WebSocket from 'ws';
import EE from './../utils/eventEmitter';
import { EEventType, EOpenEventType } from '../ts/enum';
import coolKitWs from '..';
// import _ from

type TMethod = 'message' | 'open' | 'error' | 'close' | 'reconnect';

export default class CoolKitWs {
    private static ws: WebSocketService | null = null;

    /**
     *
     * 初始化长连接
     * @param {IConfig} config
     * @returns
     * @memberof CoolKitWs
     */
    public async init(config: IConfig) {
        try {
            if ((config.userAgent === 'app' || config.userAgent === 'pc_ewelink') && (!config.at || !config.apikey || !config.appid || !config.region)) {
                throw new Error('WS:app端长连接缺少必须参数！');
            }

            if (config.userAgent === 'device' && (!config.region || !config.apikey || !config.deviceid)) {
                throw new Error('WS:设备端长连接缺少必须参数！');
            }

            const newWs = new WebSocketService(config);
            const result = await newWs.init();
            CoolKitWs.ws = newWs;
            return result;
        } catch (error) {
            throw new Error(`WS:长连接连接出错, ${error}`);
        }
    }

    /**
     *
     * 关闭长连接
     * @memberof CoolKitWs
     */
    public close() {
        const ws = this.getWs();
        ws.close(true);
    }

    /**
     * 外部函数
     * 判断长连接是否存在
     * @private
     * @returns
     * @memberof CoolKitWs
     */
    public isWsExist() {
        if (CoolKitWs.ws) {
            WebSocketService.connectConfig.debug && console.log(`WS:长连接已存在，状态为${CoolKitWs.ws.wsState === 'CLOSED' ? '已关闭' : '开启中'}`);
            return CoolKitWs.ws.wsState === 'CLOSED' ? false : true;
        }

        return false;
    }

    /**
     * 外部函数
     * 发送长连接
     * @private
     * @returns
     * @memberof CoolKitWs
     */
    public sendMessage(params: IWsParams | string) {
        const ws = this.getWs();
        ws.send(params);
    }

    /**
     *
     * 更新设备信息
     * @param {IDeviceConfig} deviceConfig
     * @returns
     * @memberof CoolKitWs
     */
    public async updateThing(deviceConfig: IDeviceConfig): Promise<IDeviceResponse | IResponse> {
        const ws = this.getWs();
        const { deviceid, ownerApikey, params } = deviceConfig;
        if (!deviceid || !ownerApikey || !params) {
            throw new Error('WS:参数不能为空');
        }
        const { sequence } = await ws.sendThing(deviceConfig, 'update');
        return await this.getMessage(sequence, deviceid);
    }

    /**
     *
     * 查询设备信息
     * @param {IQueryConfig} queryConfig
     * @returns
     * @memberof CoolKitWs
     */
    public async queryThing(queryConfig: IQueryConfig): Promise<IDeviceResponse | IResponse> {
        if (!CoolKitWs.ws || (CoolKitWs.ws && CoolKitWs.ws.wsState === 'CLOSED')) {
            return {
                error: 604,
                msg: 'Websocket is closed.',
            };
        }
        const { deviceid, ownerApikey, params } = queryConfig;
        if (!deviceid || !ownerApikey || !params) {
            throw new Error('WS:参数不能为空');
        }
        const { sequence } = await CoolKitWs.ws.sendThing(queryConfig, 'query');
        return await this.getMessage(sequence, deviceid);
    }

    /**
     *
     * 升级设备
     * @param {IUpgradeConfig} upgradeConfig
     * @returns
     * @memberof CoolKitWs
     */
    public async upgradeThing(upgradeConfig: IUpgradeConfig): Promise<IDeviceResponse | IResponse> {
        if (!CoolKitWs.ws || (CoolKitWs.ws && CoolKitWs.ws.wsState === 'CLOSED')) {
            return {
                error: 604,
                msg: 'Websocket is closed.',
            };
        }
        const { deviceid, ownerApikey, params } = upgradeConfig;
        if (!deviceid || !ownerApikey || !params) {
            throw new Error('WS:参数不能为空');
        }
        const { sequence } = await CoolKitWs.ws.sendThing(upgradeConfig, 'upgrade');
        return await this.getMessage(sequence, deviceid);
    }

    /**
     *
     * 监听长连接发送的消息
     * @param {'message'} method
     * @param {(event: { data: any; type: string; target: WebSocket }) => void} callback
     * @param {WebSocket.EventListenerOptions} [options]
     * @returns {Promise<void>}
     * @memberof CoolKitWs
     */
    public async on(method: 'message', callback: (event: { data: any; type: string; target: WebSocket }) => void, options?: WebSocket.EventListenerOptions): Promise<void>;

    /**
     *
     * 监听长连接开启消息
     * @param {'open'} method
     * @param {(event: { target: WebSocket }) => void} callback
     * @param {WebSocket.EventListenerOptions} [options]
     * @returns {Promise<void>}
     * @memberof CoolKitWs
     */
    public async on(method: 'open', callback: (event: { target: WebSocket }) => void, options?: WebSocket.EventListenerOptions): Promise<void>;

    /**
     *
     *　监听长连接错误消息
     * @param {'error'} method
     * @param {(event: { error: any; message: any; type: string; target: WebSocket }) => void} callback
     * @param {WebSocket.EventListenerOptions} [options]
     * @returns {Promise<void>}
     * @memberof CoolKitWs
     */
    public async on(
        method: 'error',
        callback: (event: { error: any; message: any; type: string; target: WebSocket }) => void,
        options?: WebSocket.EventListenerOptions
    ): Promise<void>;

    /**
     *
     * 监听长连接关闭消息
     * @param {'close'} method
     * @param {(event: { wasClean: boolean; code: number; reason: string; target: WebSocket }) => void} callback
     * @param {WebSocket.EventListenerOptions} [options]
     * @returns {Promise<void>}
     * @memberof CoolKitWs
     */
    public async on(
        method: 'close',
        callback: (event: { wasClean: boolean; code: number; reason: string; target: WebSocket }) => void,
        options?: WebSocket.EventListenerOptions
    ): Promise<void>;

    /**
     *
     * 监听长连接重连消息
     * @param {'reconnect'} method
     * @param {(errorMsg: { error: number; msg: string }) => void} callback
     * @returns {Promise<void>}
     * @memberof CoolKitWs
     */
    public async on(method: 'reconnect', callback: (errorMsg: { error: number; msg: string }) => void): Promise<void>;

    public async on(method: TMethod, callback: any) {
        const ws = this.getWs();
        if (WebSocketService.ws && ws) {
            if (method === 'reconnect') {
                EE.on(`${EOpenEventType.RECONNECT}`, (errorMsg) => callback(errorMsg));
                return;
            }
            EE.on(method, callback as unknown as any);
        }
    }

    /**
     *
     * 获取连接信息
     * @private
     * @param {string} sequence
     * @param {string} deviceid
     * @param {WebSocketService} ws
     * @returns
     * @memberof CoolKitWs
     */
    private getMessage(sequence: string, deviceid: string): Promise<IDeviceResponse | IResponse> {
        return new Promise((resolve) => {
            const { reqTimeout = 15000 } = WebSocketService.connectConfig;
            setTimeout(() => {
                resolve({
                    error: 604,
                    msg: 'ws request is timeout.',
                });
            }, reqTimeout);
            EE.once(`${EEventType.DEVICE_MSG}${sequence}${deviceid}`, (data) => resolve(data));
        });
    }

    /**
     * 内部函数
     * 获取长连接
     * @private
     * @returns
     * @memberof CoolKitWs
     */
    private getWs() {
        if (CoolKitWs.ws) {
            return CoolKitWs.ws;
        }
        throw new Error('WS:请使用 init 方法初始化长连接后再调用本方法！');
    }
}
