import { EventEmitter, Injectable } from '@angular/core';
import { HttpTransportType, HubConnection, HubConnectionBuilder, IHttpConnectionOptions, LogLevel } from '@microsoft/signalr';
import { AppConfig } from "@shared/services";
import { UtilHelper } from '../helpers';
import { CommunicationMessageModel } from '../models';

@Injectable()
export class CommunicationService {
    public connectionStatus: boolean;
    public individualConnectionStatus: boolean;

    public hubConnection: HubConnection;
    public customGroups: Array<CommunicationGroupMeta>;

    messageReceived = new EventEmitter<CommunicationMessageModel>();
    public uniqueId: string;
    public appConfigUrl: any;

    constructor() {
        this.customGroups = new Array<CommunicationGroupMeta>();
    }

    /* Initial Connections */
    public createConnection(callback?: Function) {
        const myInterval = setInterval(() => {
            const appConfigUrl = { ...AppConfig.settings };
            if (UtilHelper.isEmpty(appConfigUrl["signalR"])) {
                const url = appConfigUrl["signalR"];
                this.create(url);

                clearInterval(myInterval);
                callback && callback()
            }
        }, 10);
    }

    private create(url: string) {
        const options = {
            transport: HttpTransportType.ServerSentEvents,
            logging: LogLevel.Information,

            // accessTokenFactory: () => { return Token.getToken() }
        } as IHttpConnectionOptions;

        this.hubConnection = new HubConnectionBuilder()
            .withUrl(url, options)
            .withAutomaticReconnect()
            .build();
    }

    public startConnection(id: string, callback?: Function): void {
        this.hubConnection
            .start()
            .then(() => {
                console.info("Communication Started.");
                this.connectionStatus = true;

                this.subscribeToGroup(id, true, () => {
                    callback && callback();
                });
            })
            .catch(err => {
                console.info("Communication failed to start.");
                console.error(err);
                this.connectionStatus = false;
                //setTimeout(() => {
                //    this.startConnection(id);
                //}, 5000);
            });
    }

    public stopConnection(): void {
        this.unsubscribeToAllGroup();
        this.hubConnection
            .stop()
            .then(() => {
                console.info("Communication stopped.");
                this.connectionStatus = false;
                this.customGroups = new Array<CommunicationGroupMeta>();
            })
            .catch(err => {
                console.log("Communication failed to stop.");
                console.error(err);
                //setTimeout(() => {
                //    this.stopConnection();
                //}, 10000);
            });
    }

    /* Groups */
    public subscribeToGroup(groupName: string, isIndividual = false, onSuccess: () => void = () => { }, onFailure: () => void = () => { }) {
        if (!this.connectionStatus) {
            onFailure();
            return;
        }

        this.hubConnection.invoke("SubscribeToGroup", groupName)
            .then(() => {
                if (isIndividual) {
                    this.individualConnectionStatus = true;
                } else {
                    let group = this.customGroups.find(x => x.groupName === groupName);
                    if (!group) {
                        group = new CommunicationGroupMeta();
                        group.groupName = groupName;
                        group.status = true;
                        this.customGroups.push(group);
                    } else {
                        group.status = true;
                    }
                }
                onSuccess();
            }).catch(err => {
                console.log("Cominication failed to subscribe to group");
                console.error(err);
                if (isIndividual) {
                    this.individualConnectionStatus = false;
                } else {
                    const group = this.customGroups.find(x => x.groupName === groupName);
                    if (group) {
                        group.status = false;
                    }
                }
                //if (isIndividual) {
                //    setTimeout(() => {
                //        this.subscribeToGroup(groupName, true);
                //    }, 10000);
                //}
            });
    }

    public unsubscribeToGroup(groupName: string) {
        this.hubConnection.invoke("UnsubscribeToGroup", groupName)
            .then(() => {
                this.customGroups = this.customGroups.filter(x => x.groupName !== groupName);
            })
            .catch(err => {
                console.log("Cominication failed to unsubscribe from group");
                console.error(err);
            });
    }

    public unsubscribeToAllGroup() {
        this.customGroups.forEach(groupName => {
            this.hubConnection.invoke("UnsubscribeToGroup", groupName)
                .catch(err => {
                    console.log("Cominication failed to unsubscribe from all group");
                    console.error(err);
                });
        });
    }

    sendMessage(message: CommunicationMessageModel) {
        this.hubConnection.invoke("Communication", message);
    }

    /* Send Messages */
    public sendGlobalMessage(message: CommunicationMessageMeta) {
        this.hubConnection.invoke("CommunicationGlobal", message);
    }

    public sendGroupMessage(message: CommunicationMessageMeta) {
        this.hubConnection.invoke("CommunicationGroup", message);
    }

    /* Helpers */
    public getConnectionStatus(groupName: string): boolean | null {
        const group = this.customGroups.find(x => x.groupName === groupName);
        return group ? group.status : null;
    }

    //private subscribeToIndividualCommunication(id: string) {
    //  this.hubConnection.invoke(Wordings.subscribeIndividual, id)
    //    .then(() => {
    //      this.individualConnectionStatus = true;
    //    }).catch(err => {
    //      this.individualConnectionStatus = false;
    //      console.error(err.toString());
    //      setTimeout(() => {
    //        this.subscribeToIndividualCommunication(id);
    //      }, 5000);
    //    });
    //}

    //private unsubscribeToIndividualCommunication(id: string) {
    //  this.hubConnection.invoke(Wordings.unsubscribeIndividual, id)
    //    .catch(err => console.error(err.toString()));
    //}

}

export class CommunicationGroupMeta {
    groupName: string;
    status: boolean;
}

export class CommunicationMessageMeta {
    type: number;
    uniqueId: string;
    mainEid: string;
    subEid: string;
    message: string;
    groupName: string;
    ownerEid: string;
}
