import { withStore } from '../../../services/AxiosInstance'
import buildQuery from 'odata-query'

import { HubConnectionBuilder, LogLevel, HubConnectionState } from '@microsoft/signalr'
import { METADATA_END_POINTS } from '../../helpers/action-urls'
import { ChatHubTypes  } from "./chat-box.action.types"
import {MettaSvr_Common, DailyLog_Enums} from '../../helpers/action-enums'
//connection callbacks
const chatServerConnectionStart = () => ({
    type: ChatHubTypes.CHAT_HUB_CONNECTION_START
})


const chatServerConnectionSuccess = response => ({
    type: ChatHubTypes.CHAT_HUB_CONNECTED,
    payload: response
})



export const chatServerConnectionFailure = err => ({
    type: ChatHubTypes.CHAT_HUB_CONNECTION_FAILURE,
    payload: err
})

//message receiving
const chatReceived = response => ({
    type: ChatHubTypes.CHAT_MESSAGE_RECEIVED,
    payload: response
})

//message sending
const chatSendStart = () => ({
    type: ChatHubTypes.CHAT_MESSAGE_SEND_START
})

const chatSuccessfullySent = () => ({
    type: ChatHubTypes.CHAT_MESSAGE_SENT
})

const chatSendFailure = (err) => ({
    type: ChatHubTypes.CHAT_MESSAGE_SEND_FAILURE,
    payload: err
})

//image sending
const chatImageSendStart = () => ({
    type: ChatHubTypes.CHAT_IMAGE_SEND_START
})

const chatImageSuccessfullySent = () => ({
    type: ChatHubTypes.CHAT_IMAGE_SENT
})

//chat history fetching
const chatHistoryFetchStart = () => ({
    type: ChatHubTypes.FETCH_CHAT_HISTORY_START
})

const chatHistoryFetchSuccess = (res) => ({
    type: ChatHubTypes.FETCH_CHAT_HISTORY_SUCCESS,
    payload: res
})

export const chatHubReset = () => ({
    type: ChatHubTypes.CHAT_HUB_RESET_STATE,    
})



//exported methods to be called from user actions / UI
export const startReceivingChatAsync = () => {
    return async (dispatch, getState) => {
        const { RECEIVE_MESSAGE_NAME } = METADATA_END_POINTS.chat

        const {chatter} = getState()
        const { hubConnection } = chatter        
        hubConnection.on(RECEIVE_MESSAGE_NAME, (user, message ) => {
            // console.log('received from server: user:',user, " message: ",message)    
            dispatch(chatReceived({user, message}))    
        })

    }
}
//body:  {groupName, userName, message}
export const sendChatAsync = (body) => {
    return async (dispatch, getState) => {
        try {
            
            dispatch(chatSendStart())
            
            const { SEND_MESSAGE_NAME } = METADATA_END_POINTS.chat

            const {chatter, user} = getState()
            const { userId } = user.currentUser
            const { hubConnection } = chatter        
            const { subscriptionCode, message } = body
            await hubConnection.invoke(SEND_MESSAGE_NAME, subscriptionCode, userId , message)

            dispatch(chatSuccessfullySent())
        } catch (error) {
            dispatch(chatSendFailure(`Unable to send message: ${error}`))
        }
    }
}


export const makeConnectionChatToHubAndJoinGroupAsync = (body) => {
    return async (dispatch, getState) => {
        dispatch(chatServerConnectionStart())
        try{
            const { subscriptionCode } = body
            const {user} = getState()
            const { userId } = user.currentUser

            const { SERVER_ENDPOINT, GROUP_REGISTER_NAME } = METADATA_END_POINTS.chat
            const newConnection = new HubConnectionBuilder()
                .withUrl(`${SERVER_ENDPOINT}`)
                .configureLogging(LogLevel.Information)
                .withAutomaticReconnect()
                .build()
                if (newConnection) {
                    //1. start connection
                    await newConnection.start()
                    
                    //2. join group

                    await newConnection.invoke(GROUP_REGISTER_NAME, subscriptionCode, userId)
                    dispatch(chatServerConnectionSuccess(newConnection))
                    
                    newConnection.onclose( () => {
                        console.log('reconnecting chat in 5 secs ...')
                        dispatch(chatServerConnectionFailure({message: `closed chat connection`}))
                    })

                    newConnection.onreconnected(connectionId => {
                        dispatch(chatServerConnectionStart())
                        console.assert(newConnection.state === HubConnectionState.Connected)
                        
                        console.log( `Connection reestablished. Chat connected with connectionId "${connectionId}".`)
                        dispatch(chatServerConnectionSuccess(newConnection))
                        
                    })
                }
    
            
        }catch(ex){            
            console.log("Error is: ", ex)
            dispatch(chatServerConnectionFailure({message: `error establishing connection due to ${ex}`}))

        }
    }
}

export const uploadPhoto =  (subscriptionCode, fileReference) => {
    return async (dispatch, getState) => {
        try {
            
            dispatch(chatImageSendStart())
            const {user} = getState()                

            const { userId } = user.currentUser
            const fd = new FormData()
            fd.append("FormFile", fileReference)
            fd.append("userId", userId)
            fd.append("groupName", subscriptionCode)
            const {UPLOAD_VERSION_V1} = METADATA_END_POINTS.patient
            const {POST_USER_CHAT_IMAGE_UPLOAD} = METADATA_END_POINTS.chat
            const {errorMessage,  apiResponseStatus} = await withStore(user.currentUser.accessToken, dispatch).getService.post(`${UPLOAD_VERSION_V1}${POST_USER_CHAT_IMAGE_UPLOAD}`,fd)
            
            if (apiResponseStatus === MettaSvr_Common.APIResponseStatus.Error){
                dispatch(chatSendFailure({message: errorMessage }))
            }else{
                dispatch(chatImageSuccessfullySent())
            }
        } catch (ex) {
            dispatch(chatSendFailure({message: `exception uploading image due to: ${ex}`}))

        }
        
    }
    
}
/**
 * sample chat histry response:
 * {
    "@odata.context": "http://mettabe/odataAPI/v1/$metadata#Collection(MettaSvr.DAL.Entites.ChatMessage)",
    "value": [
        {
            "ChatId": 16,
            "MessageType": 51,
            "Message": "DR Debasish Basu has just joined the group",
            "ImageUrl": null,
            "UserId": "2b26dbe7-9309-48ca-96c8-7b56ad595bd7",
            "UserName": "DR Debasish Basu",
            "UserType": 6,
            "GroupName": "MSCFXMAMTC",
            "ProfilePicUrl": "2b26dbe7-9309-48ca-96c8-7b56ad595bd7.jpg",
            "CreatedOn": "2021-09-23T07:00:37.806407Z"
        },
        {
            "ChatId": 17,
            "MessageType": 51,
            "Message": "MR active patient 1 has just joined the group",
            "ImageUrl": null,
            "UserId": "6cfa8e8f-63c8-44db-b16d-edd1d3c43e26",
            "UserName": "MR active patient 1",
            "UserType": 8,
            "GroupName": "MSCFXMAMTC",
            "ProfilePicUrl": null,
            "CreatedOn": "2021-09-23T07:00:59.540205Z"
        },
        {
            "ChatId": 18,
            "MessageType": 49,
            "Message": "Hello pat 1",
            "ImageUrl": null,
            "UserId": "2b26dbe7-9309-48ca-96c8-7b56ad595bd7",
            "UserName": "DR Debasish Basu",
            "UserType": 6,
            "GroupName": "MSCFXMAMTC",
            "ProfilePicUrl": "2b26dbe7-9309-48ca-96c8-7b56ad595bd7.jpg",
            "CreatedOn": "2021-09-23T07:01:10.657122Z"
        },
    ]
}
 */
export const fetchChatHistoryAsync = (groupId, page=1, sortColumn="CreatedOn", sortOrder="desc", numOfRecords=MettaSvr_Common.ITEMS_PER_PAGE * 2) => {
    return async (dispatch, getState) => {
        try {
            dispatch(chatHistoryFetchStart())
            
            const {user} = getState()
            const { GET_CHAT_HISTORY } = METADATA_END_POINTS.common
            const odataQuery = {
                top: numOfRecords,
                skip: numOfRecords * (page - 1),
                count: true,
                orderBy: [`${sortColumn} ${sortOrder}`],
                filter: {                    
                    MessageType: { in: [DailyLog_Enums.ChatMessageTypeEnum.Text, DailyLog_Enums.ChatMessageTypeEnum.Image] }
                }
            }
            
            const query = buildQuery( odataQuery )
            const { CountKey, ValueKey } = MettaSvr_Common.ODATA_Keys
            const response = await withStore(user.currentUser.accessToken, dispatch).getService.get(`${GET_CHAT_HISTORY(groupId)}${query}`)              
            dispatch(chatHistoryFetchSuccess({count: response.data[CountKey], records: response.data[ValueKey]}))
        } catch (ex) {
            dispatch(chatSendFailure({message: `exception retrieve chat history due to: ${ex.response.data.title}`}))

        }
    }

}