/**
 * Created by rburson on 12/23/15.
 */


import * as React from 'react'
import {
    CvState,
    CvProps,
    CvBaseMixin,
    CvEvent,
    CvEventRegistry,
    CvEventType,
    CvLoginResult,
    CvContext,
    CvMessage,
    CvMessageType,
    CvResultCallback,
    CvSessionManager,
    CvResourceManager,
    CvActionFiredResult,
    CvActionFiredResultType
} from '../core/catreact-core'
import {Try, AppWinDef, Future, Log, SessionContext} from 'catavolt-sdk'

export interface CvLoginState extends CvState {
}

export interface CvLoginProps extends CvProps {
    loginListeners?:Array<(loginEvent:CvEvent<CvLoginResult>)=>void>
    actionListeners?:Array<(event:CvEvent<CvActionFiredResult>)=>void>
    renderer?:(cvContext:CvContext, callback:CvLoginCallback)=>{};
}

export interface CvLoginCallback {

    isLoggedIn():boolean;

    changePasswordAndLogin(url:string,
                           tenantId:string,
                           clientType:string,
                           userId:string,
                           existingPassword:string,
                           newPassword:string,
                           resultCallback?:CvResultCallback<CvLoginResult>):void;

    login(gatewayHost:string,
          tenantId:string,
          clientType:string,
          userId:string,
          password:string,
          resultCallback?:CvResultCallback<CvLoginResult>):void;

    loginDirectly(url:string,
                  tenantId:string,
                  clientType:string,
                  userId:string,
                  password:string,
                  resultCallback?:CvResultCallback<CvLoginResult>):void;
}

/*
 ***************************************************
 * Provide Login Support to other components
 ***************************************************
 */
export var CvLogin = React.createClass<CvLoginProps, CvLoginState>({

    mixins: [CvBaseMixin],

    componentDidMount: function () {
    },

    getChildContext: function () {
        return this.getDefaultChildContext();
    },

    getDefaultProps: function () {
        return {
            actionListeners: [],
            loginListeners: [],
            renderer: null
        }
    },

    render: function () {
        if (this.props.renderer) {
            return this.props.renderer(this.getChildContext().cvContext, this._getCallbackObject());
        } else {
            return null;
        }
    },

    _getCallbackObject: function ():CvLoginCallback {

        return {

            isLoggedIn: ():boolean => {
                return this.catavolt().isLoggedIn;
            },

            changePasswordAndLogin: (url:string, tenantId:string, clientType:string,
                            userId:string, existingPassword:string, newPassword:string, resultCallback?:CvResultCallback<CvLoginResult>)=> {
                this._publishActionStarted('#login');
                this._postLogin(this.catavolt().changePasswordAndLogin(url, tenantId, clientType, userId, existingPassword, newPassword), resultCallback);
            },

            login: (gatewayHost:string, tenantId:string, clientType:string,
                    userId:string, password:string, resultCallback?:CvResultCallback<CvLoginResult>)=> {
                this._publishActionStarted('#login');
                this._postLogin(this.catavolt().login(gatewayHost, tenantId, clientType, userId, password), resultCallback);
            },

            loginDirectly: (url:string, tenantId:string, clientType:string,
                            userId:string, password:string, resultCallback?:CvResultCallback<CvLoginResult>)=> {
                this._publishActionStarted('#login');
                this._postLogin(this.catavolt().loginDirectly(url, tenantId, clientType, userId, password), resultCallback);
            }

        }
    },

    _postLogin: function (loginResult:Future<AppWinDef>, resultCallback?:CvResultCallback<CvLoginResult>) {

        loginResult.onComplete((appWinDefTry:Try<AppWinDef>) => {
            this._publishActionFinished('#login');
            if (appWinDefTry.isSuccess) {
            
                CvSessionManager.storeSession(this.catavolt().sessionContextTry.success);
                
                const eventRegistry:CvEventRegistry = this.eventRegistry();
                const event:CvEvent<CvLoginResult> = {
                    type: CvEventType.LOGIN,
                    resourceId: CvResourceManager.resourceIdForObject(appWinDefTry.success, this.catavolt()),
                    eventObj: {appWinDef: appWinDefTry.success}
                };
                if(resultCallback && typeof resultCallback === 'function') {
                    resultCallback(event.eventObj);
                }
                eventRegistry.publish<CvLoginResult>(event, CvResourceManager.shouldCacheResult(this.eventRegistry()));
                this.props.loginListeners.forEach((listener)=> {
                    listener(event)
                });
            } else {
                const event:CvEvent<CvMessage> = {
                    type: CvEventType.MESSAGE,
                    eventObj: {message: 'Login failed', messageObj: appWinDefTry.failure, type: CvMessageType.ERROR}
                }
                if(resultCallback && typeof resultCallback === 'function') {
                    resultCallback(null, appWinDefTry.failure);
                }
                this.eventRegistry().publish(event, false);
            }
        });
    },

    _publishActionStarted: function (actionId:string):void {
        const e:CvEvent<CvActionFiredResult> = {
            type: CvEventType.ACTION_FIRED,
            eventObj: {
                actionId: actionId,
                type: CvActionFiredResultType.ACTION_STARTED,
                source: null,
                clientAction: false
            }
        };
        this.props.actionListeners.forEach((listener)=> {
            listener(e)
        });
        (this.eventRegistry() as CvEventRegistry).publish<CvActionFiredResult>(e, false);
    },

    _publishActionFinished: function (actionId:string):void {
        const e:CvEvent<CvActionFiredResult> = {
            type: CvEventType.ACTION_FIRED,
            eventObj: {
                actionId: actionId,
                type: CvActionFiredResultType.ACTION_COMPLETED,
                source: null,
                clientAction: false
            }
        };
        this.props.actionListeners.forEach((listener)=> {
            listener(e)
        });
        (this.eventRegistry() as CvEventRegistry).publish<CvActionFiredResult>(e, false);
    }

});
