import * as WS from 'ws';
import { EventEmitter } from 'events';
import { ACUtils } from './cube-utils';

export default class ACSocket extends EventEmitter {
    private server: WS.Server | undefined;
    private port: number = 4000;

    constructor() {
        super();
        //  heartbeat check
        setInterval(()=>{
            if (this.server) {
                this.server.clients.forEach((client:any) => {
                    if (client.isAlive === false) { 
                        client.terminate();
                        this.emit('close', {client});
                    }
                });
            }
        }, 10000);
    }
    async run(): Promise<void> {
        this.port = await ACUtils.localPort();
        this.server = new WS.Server({
            port: this.port,
            clientTracking: true
        });
        this.server.on('error', (err) => {
            this.emit('server-error', err);
        });
        this.server.on('pong', () => {
        });
        this.server.on('listening', () => {
            this.emit('listening');
        });
        this.server.on('connection', (client:any, req) => {
            client.isAlive = true;

            if (req.headers.session) {
                //  client 挂载 session
                client.session = JSON.parse(decodeURI(typeof req.headers.session === 'string' ? req.headers.session : '{}'));
            }
            this.emit('connection', {client, req});
        
            client.on('error', (e:any) => {
                client.isAlive = false ;
                this.emit('error', {client, e});
            });
            client.on('close', (e:any) => {
                client.isAlive = false;
                this.emit('close', {client, e});
            });
            client.on('pong', () => {
                client.isAlive = true;
            });
            client.on('message', (message:any) => {
                console.log(`mf-debug->${message}`);
                this.emit('message', {client, message});
            });
        });

        return new Promise<void>((resolve, rejects)=>{
            resolve();
        });
    }
    async close(): Promise<void> {
        return new Promise<void>((resolve, rejects)=>{
            if (this.server) {
                this.server.close((err)=>{
                    if (err) {
                        rejects(err);
                    } else {
                        resolve();
                    }
                });
            }
        });
    }
    //  主动断链
    async closeClient(token: string): Promise<void> {
        return new Promise<void>((resolve, rejects)=>{
            let code = -1;
            const clients = this.wsclients();
            clients.forEach(element => {
                if (token === element.session.token) {
                    element.terminate();
                    this.emit('close', { client:element });
                    code = 0;
                }
            });
            if (code === -1) {
                resolve();
            } else {
                rejects();
            }
        });
    }
    broadcase(message: ACSocketMessage): void {
        if (this.server) {
            this.server.clients.forEach((element:any) => {
                if (element.readyState === WS.OPEN) {
                    if (message.token && message.token !== element.session.token) {
                        //  条件广播
                        element.send(message.data);
                    } else {
                        //  全局广播
                        element.send(message.data);
                    }
                }
            });
        }
    }
    send(message: ACSocketMessage): void {
        if (this.server) {
            this.server.clients.forEach((element:any) => {
                if (element.readyState === WS.OPEN) {
                    if (message.token === element.session.token) {
                        //  指定发送
                        element.send(message.data);
                    }
                }
            });
        }
    }
    //  获取当前已连接的client信息
    clients(): Array<ACSocketSession> {
        const sessions = new Array();
        this.wsclients().forEach(element => {
            const info = element.session;
            info.readyState = element.readyState;
            sessions.push(info);
        });
        return sessions;
    }
    wsclients(): Array<any> {
        const clients = new Array();
        if (this.server && this.server.clients) {
            this.server.clients.forEach((element:any) => {
                if (element.isAlive === true) {
                    clients.push(element);
                }
            });
        }
        return clients;
    }
    //  建链信息
    qrvalue(): string {
        const info = this.connectInfo();
        return `alipays://platformapi/startApp?appId=80000002&action=connect&ip=${info.ip}&port=${info.port}`;
    }
    connectInfo(): ACSocketConnectInfo {
        return {
            port: this.port,
            ip: ACUtils.localIP()
        };
    }
}

export interface ACSocketMessage {
    token: string;
    data: any;
}
export interface ACSocketSession {
    token: string;
    name: string;
    os: string;
    platform: string;
}
export interface ACSocketConnectInfo {
    port: number;
    ip: string;
}