/*
 * Copyright Avaya Inc., All Rights Reserved. THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF Avaya Inc.
 * The copyright notice above does not evidence any actual or intended publication of such source code.
 * Some third-party source code components may have been modified from their original versions by Avaya.
 * The modifications are Copyright Avaya Inc., All Rights Reserved. Avaya - Confidential & Restricted.
 * May not be distributed further without written permission of the Avaya owner.
 */
/**
 * Customer Interaction Services Client SDK - EventListeners Test Application
 *
 */
(function ($) {
    'use strict';

    // Constants
    const TEAM_UPDATE_INTERVAL = 30000;
    const CLIENT_ID = 'testApp';

    // Server endpoints
    const API_URL = 'https://BREEZE-FQDN/services/UnifiedAgentController/UACAPI';
    const BROADCAST_URL = 'https://BREEZE-FQDN/services/Broadcast-UnifiedAgentController/broadcast';

    // Helper mappings
    var resourceColourMap = {
        READY: 'mdl-color--green',
        NOT_READY: 'mdl-color--orange',
        NOT_READY_PENDING: 'mdl-color--blue',
        LOGGED_OUT: 'mdl-color--grey'
    };
    var resourceStateMap = {
        READY: 'Ready',
        NOT_READY: 'Not Ready',
        NOT_READY_PENDING: 'Not Ready Pending',
        LOGGED_OUT: 'Logged Out'
    };
    var interactionIconMap = {
        VOICE: 'phone',
        WEBCHAT: 'chat',
        EMAIL: 'email',
        SMS: 'textsms',
        SOCIAL: 'people',
        VIDEO: 'video_call'
    };
    var participantIconMap = {
        AGENT: 'record_voice_over',
        SUPERVISOR: 'supervisor_account',
        CUSTOMER: 'person',

        ACTIVE: 'record_voice_over'
    };
    var interactionStateMap = {
        ALERTING: 'mdl-color--red-400',
        ACTIVE: 'mdl-color--green-400',
        HELD: 'mdl-color--orange-400'
    };
    
    // Toast message
    var $toast = $('#toast');

    // Menu tabs
    var $workTab = $('a[href="#work"].mdl-layout__tab');
    var $teamTab = $('a[href="#team"].mdl-layout__tab');
    var $contactsTab = $('a[href="#contacts"].mdl-layout__tab');

    // Agent View Cards
    var $agentCard = $('#agent-card');
    var $resourceCard = $('#resource-card');

    // Activate Agent form
    var $activateForm = $('#activate-container');
    var $agentName = $('#agent-name');
    var $agentState = $('#agent-status');
    var $profile = $('#profile');
    var $profileContainer = $('#profile-container');
    var $extension = $('#extension');
    var $profileList = $('ul[for="profile"]');

    // Toggle Agent state
    var $activateBtn = $('#agent-activate');
    var $loginBtn = $('#agent-login');
    var $goReadyBtn = $('#agent-goready');
    var $goNotReadyBtn = $('#agent-gonotready');
    var $logoutBtn = $('#agent-logout');
    var $deactivateBtn = $('#agent-deactivate');

    // Resource states
    var $voiceStatus = $('#voice-status');
    var $webchatStatus = $('#webchat-status');
    var $emailStatus = $('#email-status');
    var $smsStatus = $('#sms-status');

    // Work cards
    var $work = $('#work');
    var $interactionAddress = $('#interaction-address');
    var $startInteraction = $('#start-interaction');

    // Contacts view
    var $contactSearchString = $('#contactSearch');
    var $contactSearchBtn = $('#contact-search');
    
    // Get Auth info
    var SSOToken = $.cookie('UACCookieSession');
    var tokenData = SSOToken && parseSSOToken(SSOToken);
    
    // UAC Configuration for Avaya Customer Services SDK
    var config = {
        uacConfiguration: new AvayaCustomerServices.Config.UACConfiguration({
            enabled: true,
            clientInfo: { id: CLIENT_ID },
            serverInfo: { apiUrl: API_URL },
            notificationInfo: { broadcastUrl: BROADCAST_URL, fallbackTransport: 'websocket' },
            authenticationInfo: { enabled: true, tokens: ['Authorization'] }
        })
    };

    // Bootstrap Customer Interaction Services SDK
    var client = new AvayaCustomerServices(config);
    var clientSession = client.createClientSession();
    
    var agent, team, work;
    
    SSOToken && start();

    /**
     * Start Customer Interaction Services SDK
     */
    function start() {

        // Create token for Client SDK Authentication
        var token = {
            header: 'Authorization',
            value: SSOToken
        };

        // Set token to SDK token store and start session
        clientSession.setToken(token);

        // Display resource if acquired
        clientSession.addOnResourceAcquiredCallback(function (resource) {
            $resourceCard.find('.resources').append($('#resourceTemplate').render(resource));
        });

        // Hide resource if released
        clientSession.addOnResourceReleasedCallback(function (resource) {
            $('#resource-' + resource.channel.toLowerCase()).addClass('hide');
        });

        clientSession.getConfiguration(tokenData.authHandle).then(function(data) {
            var loadedConfig = data.configuration;
            
            // Set Agent name and default extension from API call data
            $agentName.text(data.user.displayName);
            $extension.val(data.user.resourceId);

            // Builds list of profiles from API call data and appends to dropdown list
            $.each(data.userProfileDetailsList, function (index, profile) {
                var $item = $('<li></li>')
                    .addClass('mdl-menu__item')
                    .attr('data-val', profile.userProfile.id)
                    .text(profile.userProfile.profileName)
                    .click(function () {$profileList.parent().removeClass('is-visible')});
                $profileList.append($item);
            });

            // Initialises getmdl-select component {@link https://github.com/CreativeIT/getmdl-select}
            getmdlSelect.init('#profile-container');
            $profileContainer.removeClass('hide');
            
            // check if communication service package is needed based on loaded configuration
            if(loadedConfig.isWebRTC || loadedConfig.aadsFQDN) {
                var config = {
                    logger: console
                }

                if(loadedConfig.isWebRTC) {
                    config.callUserConfiguration = {
                        incomingCall: true,
                        videoEnabled: true,
                        videoMaxBandwidthAnyNetwork: 1024
                    };
                    config.sgConfiguration = {
                        enabled: loadedConfig.isWebRTC,
                        authToken: tokenData.jwt,
                        networkConfiguration: {
                            hostName: loadedConfig.aawgFQDN,
                            port: 443,
                            isSecure: true
                        }
                    };
                }

                if(loadedConfig.aadsFQDN) {
                    config.acsConfiguration = {
                        enabled: true,
                        authToken: tokenData.jwt,
                        networkConfiguration: {
                            hostName: loadedConfig.aadsFQDN,
                            port: 443,
                            isSecure: true
                        }
                    };
                }

                $activateBtn.on('click', communicationServicesActivate.bind(null, data.user));
                // Enable activate button
                $activateBtn.removeAttr('disabled');

                var cpConfig = new AvayaCustomerServices.Config.CPConfiguration(config);
                clientSession.setConfig({ cpConfiguration: cpConfig });
            }
            else {
                $activateBtn.on('click', activate.bind(null, data.user));
                // Enable activate button
                $activateBtn.removeAttr('disabled');
                
                startClientSession();
            }
        });
    }

    /**
      * Common code to be executed to start Client Session
      *
      * @private
      * @returns {void}
      */
    function startClientSession() {
        // And start the client session (initiates atmosphere)
        clientSession.start();
        
        // Initialise Agent module
        agent = clientSession.createAgent();

        // Attach listener for agent activate event
        agent.addOnActivatedCallback(function (data) {
            // Update Agent name and update UI
            $agentName.text(agent.data.firstName + ' ' + agent.data.lastName);
            updateStateUI();

            // Get Team state and display
            setInterval(function() {
                team.getTeamState(data.role);
            }, TEAM_UPDATE_INTERVAL);
            team.getTeamState(data.role);
            $teamTab.removeClass('hide');
        });

        // Attach listener for agent deactivate event
        agent.addOnDeactivatedCallback(function () {
            $.cookie('UACCookieSession', '', { expires: -1, path: '/' });
            window.location.reload();
        });

        // Attach listener for agent login pending event
        agent.addOnStateLoginPendingCallback(function (data) {
            updateStateUI();
        });

        // Attach listener for agent ready event
        agent.addOnStateReadyCallback(function (data) {
            $workTab.removeClass('hide');
            updateStateUI();
        });

        // Attach listener for agent not ready pending event
        agent.addOnStateNotReadyPendingCallback(function (data) {
            updateStateUI();
        });

        // Attach listener for agent not ready event
        agent.addOnStateNotReadyCallback(function (data) {
            updateStateUI();
        });

        // Attach listener for agent logout pending event
        agent.addOnStateLogoutPendingCallback(function (data) {
            updateStateUI();
        });

        // Attach listener for agent logged out event
        agent.addOnStateLoggedOutCallback(function (data) {
            $workTab.addClass('hide');
            updateStateUI();
        });

        // Attach listener for agent unknown state event
        agent.addOnStateUnknownCallback(function (data) {
            updateStateUI();
        });

        // Attach event listener to login button click
        $loginBtn.on('click', function () {
            agent.login();
        });

        // Attach event listener to go ready button click
        $goReadyBtn.on('click', function () {
            agent.goReady();
        });

        // Attach event listener to go not ready button click
        $goNotReadyBtn.on('click', function () {
            agent.goNotReady();
        });

        // Attach event listener to logout button click
        $logoutBtn.on('click', function () {
            agent.logout();
        });

        // Attach event listener to deactivate button click
        $deactivateBtn.on('click', function () {
            agent.deactivate();
        });
        
        // Initialise Work module
        work = clientSession.createWork();

        $.views.helpers({
            icon: function (channel) {
                return interactionIconMap[channel];
            },
            state: function (state) {
                return interactionStateMap[state];
            },
            address: function (direction, originatingAddress, destinationAddress) {
                if (direction === 'INCOMING') {
                    return 'Incoming Address: ' + originatingAddress;
                }
                return 'Outbound Address: ' + destinationAddress;
            },
            participantIcon: function (type, state) {
                return participantIconMap[state] || participantIconMap[type];
            }
        });

        // Attach listener to new interaction event
        work.addOnInteractionCreatedCallback(function (message) {

            // Search interaction collection to find interaction by id
            var collection = work.getInteractions();
            var interaction = collection.find({ id: message.id });

            if (message.channel === 'VIDEO') {
                $work.append($('#interactionVideoTemplate').render(interaction.data));
            } else {
                $work.append($('#interactionTemplate').render(interaction.data));
            }
            updateInteractionParticipantStateUI(interaction.data);

            interaction.addOnInteractionActiveCallback(function (data) {
                updateInteractionUI(data);
            });
            interaction.addOnInteractionHeldCallback(function (data) {
                updateInteractionUI(data);
            });
            interaction.addOnInteractionUnheldCallback(function (data) {
                updateInteractionUI(data);
            });
            /*
             * In test purpose this callback is being fired automatically in 5 secs
             * after outgoing interaction has been initiated on mock server.
             * It simulates remote participant accepted interaction event.
            */
            interaction.addOnRemoteParticipantAcceptedCallback(function (data) {
                var destinationAddress = interaction.data.destinationAddress,
                    remoteParticipant = _.find(interaction.data.participants, { 'participantAddress' : destinationAddress });

                remoteParticipant.participantState = 'ACTIVE';
                updateInteractionParticipantStateUI(interaction.data);
            });
            interaction.addOnInteractionMediaAddedCallback(function (data) {

                var interactionMedia = interaction.getInteractionMedia();

                if (interaction.data.channel === 'EMAIL') {
                    interactionMedia.addMessageReceivedCallback(function (message) {
                        $('#' + interaction.id).find('.email-panel').append($('#emailTemplate').render(message));
                    });
                } else {
                    $('#' + interaction.id).find('.chat-panel').append($('#chatTemplate').render(data));

                    interactionMedia.addMessageReceivedCallback(function () {
                        $('#' + interaction.id).find('.chat-panel-content').html($('#chatMessageTemplate').render(interactionMedia));
                    });

                    interactionMedia.addOnIsTypingCallback(function (message) {

                        $('#' + interaction.id).find('.chat-panel-content-typing').html('<div><span>' + message.participant.participantName + ': </span>is typing....</div>');
                        setTimeout(function () {
                            $('#' + interaction.id).find('.chat-panel-content-typing').html('');
                        }, 4000);
                    });

                    $('#' + interaction.id).find('.chat-panel-content').html($('#chatMessageTemplate').render(data));

                    $('#' + interaction.id).find('.chat-panel form').on('submit', function (event) {
                        event.preventDefault();
                        var chat = $('#' + interaction.id).find('.chat-panel input').val();
                        $('#' + interaction.id).find('.chat-panel input').val('');
                        interactionMedia.send(chat);
                    });
                }
            });

            interaction.addOnInteractionVideoUpdatedCallback(function (data) {
                if (data.direction === 'local') {
                    onLocalVideoUpdated(interaction, data);
                } else 
                if (data.direction === 'remote') {
                    onRemoteVideoUpdated(interaction, data);
                }
            });
            
            $('#' + interaction.id + ' .accept').on('click', function () {
                interaction.accept();
            });

            $('#' + interaction.id + ' .hold').on('click', function () {
                interaction.hold();
            });

            $('#' + interaction.id + ' .unhold').on('click', function () {
                interaction.unhold();
            });

            $('#' + interaction.id + ' .transfer').on('click', function () {
                var dialog = document.querySelector('dialog.transfer');
                dialog.querySelector('.close').addEventListener('click', function() {
                    dialog.open && dialog.close();
                });
                dialog.querySelector('.submit').addEventListener('click', function() {
                    var address = $(dialog).find('input').val();
                    interaction.singleStepTransfer(address);
                    dialog.open && dialog.close();
                });
                dialog.showModal();
            });

            $('#' + interaction.id + ' .consult').on('click', function () {
                var dialog = document.querySelector('dialog.consult');
                dialog.querySelector('.close').addEventListener('click', function() {
                    dialog.open && dialog.close();
                });
                dialog.querySelector('.submit').addEventListener('click', function() {
                    var address = $(dialog).find('input').val();
                    interaction.consult(address);
                    dialog.open && dialog.close();
                });
                dialog.showModal();
            });

            $('#' + interaction.id + ' .complete-transfer').on('click', function () {
                interaction.completeTransfer();
            });

            $('#' + interaction.id + ' .complete-conference').on('click', function () {
                interaction.completeConference();
            });

            $('#' + interaction.id + ' .end').on('click', function () {
                interaction.end();
            });
            
            $toast[0].MaterialSnackbar.showSnackbar({ message: 'Incoming interaction. Please open Work View to see updates.' });
        });

        // Detach listeners and remove element
        work.addOnInteractionDeletedCallback(function (data) {
            $('#' + data.id + ' button').off('click', '**');
            $('#' + data.id).remove();
        });

        $startInteraction.on('click', function () {
            var address = $interactionAddress.val();
            work.createInteraction('VOICE', address);
        });

        /*************************************
         *         TEAM EXAMPLE START         *
         *************************************/

        team = clientSession.createTeam();

        var memberTemplate = $.templates("#memberTemplate");

        team.addOnTeamMembersAddedCallback(function (teamMembers) {

            $('#team-view > tbody').html('');

            $.each(teamMembers, function (index, member) {
                member.displayName += (member.isSelf ? ' (me)' : '');
                $('#team-view > tbody').append(memberTemplate.render(member));
            });
        });

        /**
         * Helper function to update Agent state UI
         */
        function updateStateUI() {
            var state = agent.state ? agent.state.replace(/_/g, ' ').toLowerCase() : 'unknown';
            $agentState.text(state).css('textTransform', 'capitalize');
            agent.data.isActivated ? $activateBtn.addClass('hide') : $activateBtn.removeClass('hide');
            agent.data.isActivated ? $activateForm.addClass('hide') : $activateForm.removeClass('hide');
            agent.data.isActivated ? $resourceCard.removeClass('hide') : $activateForm.addClass('hide');
            agent.capabilities.canLogin ? $loginBtn.removeClass('hide') : $loginBtn.addClass('hide');
            agent.capabilities.canSetReady ? $goReadyBtn.removeClass('hide') : $goReadyBtn.addClass('hide');
            agent.capabilities.canSetNotReady ? $goNotReadyBtn.removeClass('hide') : $goNotReadyBtn.addClass('hide');
            agent.capabilities.canLogout ? $logoutBtn.removeClass('hide') : $logoutBtn.addClass('hide');
            agent.capabilities.canDeactivate ? $deactivateBtn.removeClass('hide') : $deactivateBtn.addClass('hide');

            $.each(resourceColourMap, function (state, className) {
                $('#resource-card .section__circle-container__circle').removeClass(className);
            });

            $.each(agent.data.resourceStates, function(resource, data) {
                var $resource = $('#resource-' + resource.toLowerCase());
                $resource.find('.section__circle-container__circle').addClass(resourceColourMap[data.state]);
                $resource.find('span.state').text(resourceStateMap[data.state]);
            });
        }

        /**
         * Helper function to update interaction UI
         */
        function updateInteractionUI(interaction) {
            var $interaction = $('#' + interaction.id);
            $interaction.find('.state').text(interaction.state);
            
            var $accept = $interaction.find('.accept');
            var $hold = $interaction.find('.hold');
            var $unhold = $interaction.find('.unhold');
            var $transfer = $interaction.find('.transfer');
            var $consult = $interaction.find('.consult');
            var $completeTransfer = $interaction.find('.complete-transfer');
            var $completeConference = $interaction.find('.complete-conference');
            var $end = $interaction.find('.end');
            
            var $media = $interaction.find('.media');
            
            var $chatPanel = $interaction.find('.chat-panel');
            var $emailPanel = $interaction.find('.email-panel');

            $accept && (interaction.capabilities.canAccept ? $accept.removeClass('hide') : $accept.addClass('hide'));
            $hold && (interaction.capabilities.canHold ? $hold.removeClass('hide') : $hold.addClass('hide'));
            $unhold && (interaction.capabilities.canUnhold ? $unhold.removeClass('hide') : $unhold.addClass('hide'));
            $transfer && (interaction.capabilities.canSingleStepTransfer ? $transfer.removeClass('hide') : $transfer.addClass('hide'));
            $consult && (interaction.capabilities.canConsult ? $consult.removeClass('hide') : $consult.addClass('hide'));
            $completeTransfer && (interaction.capabilities.canTransferComplete ? $completeTransfer.removeClass('hide') : $completeTransfer.addClass('hide'));
            $completeConference && (interaction.capabilities.canConferenceComplete ? $completeConference.removeClass('hide') : $completeConference.addClass('hide'));
            $end && (interaction.capabilities.canEnd ? $end.removeClass('hide') : $end.addClass('hide'));

            $media && (interaction.state !== 'ALERTING' ?  $media.removeClass('hide') : $media.addClass('hide'));
            
            $.each(interactionStateMap, function (state, className) {
                $interaction.find('header').removeClass(className);
            });
            $interaction.find('header').addClass(interactionStateMap[interaction.state]);

            var $participantsPanel = $interaction.find('.participants-panel');
            $participantsPanel.html($('#participantTemplate').render(interaction));
            $participantsPanel.removeClass('hide');

            $chatPanel && $chatPanel.removeClass('hide');
            $emailPanel && $emailPanel.removeClass('hide');
        }

        /**
         * Helper function to update participant state UI
         */
        function updateInteractionParticipantStateUI(interaction) {
            var $interaction = $('#' + interaction.id);

            var $participantsPanel = $interaction.find('.participants-panel');
            $participantsPanel.html($('#participantTemplate').render(interaction));
            $participantsPanel.removeClass('hide');
        }
    }
    
    /**
     * Stop Client session
     *
     * @private
     * @returns {void}
     */
    function stop() {
        clientSession.stop();
    }
    
    /**
     * Activate User
     *
     * @private
     * @param {Object} user User data
     * @returns {void}
     */
    function activate(user) {
        var profile = $profile.attr('data-val');
        var extension = $extension.val();
        agent.activate(user.userHandle, profile, extension);
    }
    
    /**
     * Activate User with the communication services package
     *
     * @private
     * @returns {Object}
     */
    function communicationServicesActivate(user) {
        // Event listener called on successful user registration
        clientSession.addOnUserRegistrationSuccessfulCallback(activate.bind(null, user));

        // Event listener called on failed user registration
        clientSession.addOnUserRegistrationFailedCallback(onUserRegistrationFailed);

        // Start client session
        startClientSession();

        var contactTemplate = $.templates("#contactTemplate");

        // Start contacts service
        var contacts = clientSession.createContacts();

        // Event Listener called when contacts service available
        contacts.addOnContactsAvailableCallback(function () {
            $contactSearchBtn.removeAttr('disabled');
            // the contacts tab will be hidden until the service becomes available
            $contactsTab.removeClass('hide');
        });

        // Event Listener called when contacts service unavailable
        contacts.addOnContactsUnavailableCallback(function () {
            $contactSearchBtn.attr('disabled', 'disabled');
        });

        // Event Listener called when contact search failed
        contacts.addOnContactsSearchFailedCallback(function (searchId, error) {
            $toast[0].MaterialSnackbar.showSnackbar({ message: error });
        });

        // Event Listener called when contact search completed
        contacts.addOnContactsSearchCompletedCallback(function (searchId, searchResults) {
            $('#contacts-view > tbody').html('');
            for (var contactId in searchResults) {
                var contactData = searchResults[contactId];
                
                var informationToDisplay = {
                    displayName: contactData.displayName ? contactData.displayName : contactData.firstName + ' ' + contactData.lastName,
                    number: contactData.phoneNumbers.length > 0 ? contactData.phoneNumbers[0].number : ''
                }
                $('#contacts-view > tbody').append(contactTemplate.render(informationToDisplay));
            }
        });

        $contactSearchBtn.on('click', function () {
           var searchString = $.trim($contactSearchString.val());
           if(searchString) {
               contacts.search(searchString, 15); 
           }
        });
    }
    
    
    /**
     * Callback to execute when Communication Services package User registration has failed
     *
     * @private
     * @param {object} error
     * @returns {void}
     */
    function onUserRegistrationFailed(error) {
        $toast[0].MaterialSnackbar.showSnackbar({ message: error.message });
    }
    
    /**
     * Event listener called when the remote video stream has been updated.
     *
     * @private
     * @param {object} interaction
     * @param data object
     * @returns {void}
     */
    function onRemoteVideoUpdated(interaction, data) {
        var $interaction = $('#' + interaction.id);
        var $remoteVideo = $interaction.find('.remote-video');
        var $remoteVideoDisabled = $interaction.find('.remote-video-disabled');
        
        if (data && data.stream) {
            $remoteVideo.removeClass('hide');
            $remoteVideo.attr('src', URL.createObjectURL(data.stream));
            $remoteVideoDisabled.addClass('hide');
        } else {
            $remoteVideo.addClass('hide');
            $remoteVideoDisabled.removeClass('hide');
        }
    }
    
    /**
     * Event listener called when the local video stream has been updated.
     *
     * @private
     * @param {object} interaction
     * @param data object
     * @returns {void}
     */
    function onLocalVideoUpdated(interaction, data) {
        var $interaction = $('#' + interaction.id);
        var $localVideo = $interaction.find('.local-video');
        var $localVideoDisabled = $interaction.find('.local-video-disabled');
        
        if (data && data.stream) {
            $localVideo.removeClass('hide');
            $localVideo.attr('src', URL.createObjectURL(data.stream));
            $localVideoDisabled.addClass('hide');
        } else {
            $localVideo.addClass('hide');
            $localVideoDisabled.removeClass('hide');
        }
    }
    
    /**
     * Parse JSON Web Token
     *
     * @private
     * @returns {Object}
     */
    function parseSSOToken(token) {
        var parsedJWT;
        var encodedJWT = token.split(' ')[1];
        if (!encodedJWT) return;

        var payload = encodedJWT.split('.')[1];
        if (!payload) return;

        try {
            parsedJWT = JSON.parse(window.atob(payload));
        } catch(error) {
            parsedJWT = {};
        }
        return {
            authHandle: parsedJWT.sub,
            expires: parsedJWT.exp,
            jwt: encodedJWT
        };
    }

})(jQuery);