import React, {useEffect} from 'react'
import { gql } from '../helpers'
import { actionChatsCount } from '../actions'
import { createStore, combineReducers, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import {
    actionOnMsg,
    actionOnChat,
    actionOnChatLeft,
    actionFullLogout,
} from '../actions'
import io from 'socket.io-client'
import { actionFullChatList, actionFullMsgsByChat, actionGetChatById } from "../actions";


export function promiseReducer(state, { type, status, payload, error, name }) {
    if (!state) {
        return {}
    }
    if (type === 'PROMISE') {
        return {
            ...state,
            [name]: {
                status: status,
                payload:
                    (status === 'PENDING' &&
                        state[name] &&
                        state[name].payload) ||
                    payload,
                error: error,
            },
        }
        //для пользы при работе с промисами надо бы пока PENDING не делать payload undefined
        //при наличии старого payload
    }
    return state
}

const actionPending = (name) => ({ type: 'PROMISE', status: 'PENDING', name })
const actionResolved = (name, payload) => ({
    type: 'PROMISE',
    status: 'RESOLVED',
    name,
    payload,
})
const actionRejected = (name, error) => ({
    type: 'PROMISE',
    status: 'REJECTED',
    name,
    error,
})

export const actionPromise = (name, promise) => async (dispatch) => {
    dispatch(actionPending(name))
    try {
        let data = await promise
        dispatch(actionResolved(name, data))
        return data
    } catch (error) {
        dispatch(actionRejected(name, error))
    }
}



// ------------------



function jwtDecode(token) {
    try {
        const decoded = JSON.parse(atob(token.split('.')[1]))
        return decoded
    } catch (err) {
        console.log(err)
    }
}

export function authReducer(state, { type, token }) {
    if (!state) {
        if (localStorage.authToken) {
            token = localStorage.authToken
            type = 'AUTH_LOGIN'
        } else {
            return {}
        }
    }
    if (type === 'AUTH_LOGIN') {
        const payload = jwtDecode(token)
        if (typeof payload === 'object') {
            localStorage.authToken = token
            return {
                ...state,
                token,
                payload,
            }
        } else {
            console.error(
                'Токен ' + localStorage.authToken + ' неверный и был удален'
            )
            delete localStorage.authToken
            return state || {}
        }
    }
    if (type === 'AUTH_LOGOUT') {
        delete localStorage.authToken
        return {}
    }
    return state
}

export const actionAuthLogin = (token) => ({ type: 'AUTH_LOGIN', token })
export const actionAuthLogout = () => ({ type: 'AUTH_LOGOUT' })



// -----------------------------------



// const chats = {
//   chats: [
//     {_id: '333', title: 'moiChat2', avatar: null, lastModified: 'segodnya', owner: {login: 'ya'}, members:[]},
//     {_id: '222', title: 'moiChat', avatar: null, lastModified: 'vchera', owner: {login: 'ya'}, members:[]}
//   ],
//   messages: {
//     '222': [
//       {text: 'uuu'}, {text: 'uuuuuu'}
//     ],
//     '333': [
//       {text: 'UUU'}, {text: 'U'}
//     ]
//   }
// }

// payload - или массив чатов или массив сообщений или 1 чат
export function chatsReducer(state, { type, payload }) {
    if (!state) {
        return {
        }   
    }
    function refreshMsgs(newMsgs, oldMsgs) {
        const msgState = [...oldMsgs]

        for (const newMsg of newMsgs || []) {
            const currIndex = msgState.findIndex(
                (oldMsg) => oldMsg._id === newMsg._id
            )

            if (currIndex === -1) {
                msgState.push(newMsg)
            } else {
                msgState[currIndex] = newMsg
            }
        }
        const newMsgState = msgState.sort((a, b) => {
            if (a._id > b._id) {
                return 1
            }
            if (a._id < b._id) {
                return -1
            }
            return 0
        })

        return newMsgState
    }

    function getInfoAboutNext(msgState) {
        const informedState = []

        for (let i = 0; i < msgState.length; i++) {
            const msg = msgState[i]

            msg.nextMsg = msgState[i + 1] || null
            informedState.push(msg)
        }

        return informedState
    }

    function sortChats(unsortedChats) {
        return Object.fromEntries(
            Object.entries(unsortedChats).sort((a, b) => {
                if (a[1].lastModified > b[1].lastModified) {
                    return -1
                }
                if (a[1].lastModified < b[1].lastModified) {
                    return 1
                }
                return 0
            })
        )
    }

    const types = {
        CHATS() {
            if (payload) {
                const oldChats = { ...state }

                // перебираем новые чаты
                for (const chat of payload) {
                    // находим старый чат с ид нового
                    const oldChat = oldChats[chat._id]
                    // если его еще нет, то просто записываем
                    if (!oldChat) {
                        oldChats[chat._id] = { ...chat } 
                        // если есть, то идем по свойствам нового чата
                    } else
                        for (const key in chat) {
                            // записываем значение свойства нового и старого чата
                            const oldValue = oldChat[key]
                            const newValue = chat[key]

                            // проверяем наличие значений
                            // если оба значения или только новое, переходим к проверке на массив сообщений
                            if (newValue) {
                                // если массив сообщений, то вызываем соответствующие функции слияния
                                if (key === 'messages') {
                                    oldChats[chat._id][key] = getInfoAboutNext(
                                        refreshMsgs(newValue, oldValue)
                                    )
                                } else {
                                    oldChats[chat._id][key] = newValue //-----------------------------------
                                }

                                // если есть только старое, записать старое (можно ничего не делать)
                            } else {
                                oldChats[chat._id][key] = oldValue //-------------------------------------
                            }
                        }
                }

                const newState = sortChats(oldChats)

                return newState
            }
            return state
        },

        CHAT_LEFT() {
            const { [payload._id]: removed, ...newState } = state // eslint-disable-line
            return newState
        },

        CHATS_CLEAR() {
            return {}
        },

        MSGS() {
            if (payload && payload.length > 0) {
                const chatId = payload[0]?.chat?._id

                const msgState = state[chatId]?.messages || []

                const newMsgState = getInfoAboutNext(
                    refreshMsgs(payload, msgState)
                )

                const newState = {
                    ...state,
                    [chatId]: {
                        ...state[chatId],
                        messages: newMsgState,
                    },
                }

                return newState
            }
            return state
        },
    }
    if (type in types) {
        return types[type]()
    }
    return state
}

export const actionChatList = (chats) => ({ type: 'CHATS', payload: chats })
export const actionChatOne = (chat) => ({ type: 'CHATS', payload: [chat] })
export const actionChatLeft = (chat) => ({ type: 'CHAT_LEFT', payload: chat })
export const actionChatsClear = () => ({ type: 'CHATS_CLEAR' })

export const actionMsgList = (msgs) => ({ type: 'MSGS', payload: msgs })
export const actionMsgOne = (msg) => ({ type: 'MSGS', payload: [msg] })



// -------------------------------





export const actionUserFindOne = (userId, name = 'findUserOne') =>
    actionPromise(
        name,
        gql(
            `query findUserOne($q: String) {
      UserFindOne (query: $q){
         _id
         createdAt
         login
         nick
         avatar {
            _id
            url
         }
         chats{
            avatar {
                _id
                url
             }
            messages {
                _id
                createdAt
                text
                        owner {
                          _id
                          createdAt
                          login
                          nick
                        }
                media {
                  _id
                  createdAt
                  text
                  url
                  originalFileName
                  type
                }
              }
            _id
            createdAt
            title
            lastMessage {
                _id
                createdAt
                text
            }
        }
    }
}
`,
            {
                q: JSON.stringify([{ _id: userId }]),
            }
        )
    )

export const actionAboutMe = () => async (dispatch, getState) => {
    let { auth } = getState()
    let id = auth?.payload?.sub?.id
    if (id) {
        await dispatch(actionUserFindOne(id, 'myProfile'))
        await dispatch(actionChatsCount(id))
    }
}



// -----------------------




// let initialState = localStorage.getItem('state')

export const store = createStore(
    combineReducers({
        auth: authReducer,
        chats: chatsReducer,
        promise: promiseReducer,
    }),
    // initialState ? {chats: JSON.parse(initialState)} : {},
    applyMiddleware(thunk)
)

store.dispatch(actionAboutMe())

// store.subscribe(() => console.log(store.getState()))
// window.onbeforeunload = () => window.localStorage.setItem('state', JSON.stringify(store.getState().chats) )

///////////////////////////////////////////////////////////////////

export const socket = io('ws://chat.ed.asmer.org.ua')

socket.on('jwt_ok', (data) => console.log(data))
socket.on('jwt_fail', (error) => {
    console.log(error)
    store.dispatch(actionFullLogout())
})

socket.on('msg', (msg) => {
    console.log('пришло смс')
    store.dispatch(actionOnMsg(msg))
})

socket.on('chat', (chat) => {
    console.log('нас добавили в чат')
    store.dispatch(actionOnChat(chat))

    const state = store.getState()
    socket.disconnect(true)
    socket.connect()
    socket.emit('jwt', state.auth.token)
})

socket.on('chat_left', (chat) => {
    console.log('нас выкинули из чата')
    store.dispatch(actionOnChatLeft(chat))
})

store.subscribe(() => console.log(store.getState()));
console.log(store.getState())

if(store.getState().auth.token){
    store.dispatch(actionFullChatList(store.getState().auth.payload?.sub.id))
}



const bodyColor = () => {return document.body.style.background = '#eee'}
bodyColor()

// store.dispatch(actionGetChatById("633b2f0c55e76f7ddb1eae97"))

  
