import {
    createSlice,
    createAsyncThunk,
    createEntityAdapter,
    createSelector,
} from '@reduxjs/toolkit'
import { request } from 'api'
import { getFeed, selectUserPosts } from 'features/posts/postsSlice'
import { parsePosts } from 'features/posts/utils'
import { userUpdated as authUserUpdated } from 'store/authSlice'

let usersComparer = (a, b) => b.followers_count - a.followers_count
const usersAdapter = createEntityAdapter({
    selectId: user => user.screen_name,
    // sortComparer: usersComparer
})
const initialState = usersAdapter.getInitialState({
    user_suggests_status: 'idle',
    user_timeline_status: 'idle',
    user_timeline_page: 0,

    user_update_status: 'idle',

    user_friendlist_status: 'idle',
    user_friendlist_page: 0,

    user_followerlist_status: 'idle',
    user_followerlist_page: 0,

    post_likes_status: 'idle',
    post_likes_page: 0,
    post_reposts_status: 'idle',
    post_reposts_page: 0,
})

export const updateUserDetails = createAsyncThunk(
    'users/updateUserDetails',
    async (body, { dispatch }) => {
        let { user } = await request('/api/updateuser', { body, dispatch })
        if (!user) throw Error('User feild nill in responce')
        dispatch(authUserUpdated(user))
        return dispatch(userAdded(user))
    }
)

export const getUserSuggests = createAsyncThunk(
    'users/getUserSuggests',
    async (_, { dispatch }) => {
        let data = await request('/api/users', { dispatch })
        // console.log(data.users)
        return data.users
    }
)
export const getUserTimeline = createAsyncThunk(
    'users/getUserTimeline',
    async (username, { dispatch, getState }) => {
        let { user_timeline_page: p } = getState().users
        let l = selectUserPosts(getState(), username).length
        if (!l || l === 0) {
            dispatch(resetTimelinePage())
            p = 0
        }
        let url = `/api/user_timeline/${username}?p=${p + 1}`
        let { posts, user } = await request(url, { dispatch })
        if (user) {
            dispatch(userAdded(user))
        }
        dispatch(parsePosts(posts))
        return posts.length
    }
)

export const followUser = createAsyncThunk(
    'users/folllowUser',
    async (username, { dispatch, getState }) => {
        dispatch(followingChanged({ username, following: true }))
        username = encodeURIComponent(username)
        await request(`/api/follow/${username}`, { dispatch, body: {} })
        let feedStatus = getState().posts.feed_status
        if (feedStatus === 'done') dispatch(getFeed())
    }
)
export const unFollowUser = createAsyncThunk(
    'users/unFolllowUser',
    async (username, { dispatch }) => {
        dispatch(followingChanged({ username, following: false }))
        username = encodeURIComponent(username)
        return request(`/api/unfollow/${username}`, { dispatch, body: {} })
    }
)
export const getFollowers = createAsyncThunk(
    'users/getFollowers',
    async (username, { dispatch, getState }) => {
        let {
            users: { user_followerlist_page: p },
        } = getState()
        let l = selectFollowers(getState(), username).length
        if (!l) {
            dispatch(resetFollowerlistPage())
            p = 0
        }
        p = parseInt(p)
        username = encodeURIComponent(username)
        let { users = [] } = await request(`/api/followers/${username}?p=${p + 1}`, { dispatch })
        users = users || []
        if (!users.length) return
        users = users
            .map(user => ({ ...user, follower_of: decodeURIComponent(username) }))
            .filter(Boolean)
        dispatch(usersAdded(users))
        return users.length
    }
)
export const getFriends = createAsyncThunk(
    'users/getFriends',
    async (username, { dispatch, getState }) => {
        let {
            users: { user_friendlist_page: p },
        } = getState()
        let l = selectFriends(getState(), username).length
        if (!l) {
            dispatch(resetFriendlistPage())
            p = 0
        }
        p = parseInt(p)
        username = encodeURIComponent(username)
        let { users = [] } = await request(`/api/friends/${username}?p=${p + 1}`, { dispatch })
        users = users || []
        if (!users.length) return
        users = users
            .map(user => ({ ...user, friend_of: decodeURIComponent(username) }))
            .filter(Boolean)
        dispatch(usersAdded(users))
        return users.length
    }
)
export const getLikes = createAsyncThunk(
    'users/getLikes',
    async (postId, { dispatch, getState }) => {
        try {
            let {
                users: { post_likes_page: p },
            } = getState()
            p = parseInt(p)
            let l = selectLikes(getState(), postId).length
            if (!l) {
                dispatch(resetLikesPage())
                p = 0
            }
            let { users = [] } = await request(`/api/post/${postId}/likes?p=${p + 1}`, { dispatch })
            users = users || []
            if (!users.length) return
            users = users.map(user => ({ ...user, liked_post: postId })).filter(Boolean)
            dispatch(usersAdded(users))
            return users.length
        } catch (err) {
            console.log(err)
            throw err
        }
    }
)
export const getReposts = createAsyncThunk(
    'users/getReposts',
    async (postId, { dispatch, getState }) => {
        let {
            users: { post_reposts_page: p },
        } = getState()
        p = parseInt(p)
        let l = selectReposts(getState(), postId).length
        if (!l) {
            dispatch(resetRepostsPage())
            p = 0
        }
        let { users = [] } = await request(`/api/post/${postId}/reposts?p=${p + 1}`, { dispatch })
        users = users || []
        if (!users.length) return
        users = users.map(user => ({ ...user, reposted_post: postId })).filter(Boolean)
        dispatch(usersAdded(users))
        return users.length
    }
)

const usersSlice = createSlice({
    name: 'users',
    initialState,
    reducers: {
        followingChanged: (state, action) => {
            let { username, following } = action.payload
            usersAdapter.updateOne(state, {
                id: username,
                changes: {
                    following,
                    new: true,
                },
            })
        },
        resetTimelinePage: state => {
            state.user_timeline_page = 0
        },
        resetFollowerlistPage: state => {
            state.user_followerlist_page = 0
        },
        resetFriendlistPage: state => {
            state.user_friendlist_page = 0
        },
        resetLikesPage: state => {
            state.post_likes_page = 0
        },
        resetRepostsPage: state => {
            state.post_reposts_page = 0
        },
        userAdded: usersAdapter.upsertOne,
        usersAdded: usersAdapter.upsertMany,
        usersAddedDontUpdate: usersAdapter.addMany,
    },
    extraReducers: {
        [getUserSuggests.rejected]: state => {
            state.user_suggests_status = 'error'
        },
        [getUserSuggests.pending]: state => {
            state.user_suggests_status = 'loading'
        },
        [getUserSuggests.fulfilled]: (state, action) => {
            state.user_suggests_status = 'idle'
            // console.log(action.payload)
            usersAdapter.addMany(state, action.payload)
        },
        [getUserTimeline.rejected]: state => {
            state.user_timeline_status = 'error'
        },
        [getUserTimeline.pending]: state => {
            state.user_timeline_status = 'loading'
        },
        [getUserTimeline.fulfilled]: (state, action) => {
            let length = action.payload
            if (length > 0) {
                state.user_timeline_status = 'idle'
                state.user_timeline_page += 1
            } else state.user_timeline_status = 'done'
        },
        [updateUserDetails.rejected]: state => {
            state.user_update_status = 'error'
        },
        [updateUserDetails.pending]: state => {
            state.user_update_status = 'pending'
        },
        [updateUserDetails.fulfilled]: state => {
            state.user_update_status = 'idle'
        },

        [getFollowers.rejected]: state => {
            state.user_followerlist_status = 'error'
        },
        [getFollowers.pending]: state => {
            state.user_followerlist_status = 'loading'
        },
        [getFollowers.fulfilled]: (state, action) => {
            const length = action.payload
            if (length > 0) {
                state.user_followerlist_status = 'idle'
                state.user_followerlist_page += 1
            } else state.user_followerlist_status = 'done'
        },

        [getFriends.rejected]: state => {
            state.user_friendlist_status = 'error'
        },
        [getFriends.pending]: state => {
            state.user_friendlist_status = 'loading'
        },
        [getFriends.fulfilled]: (state, action) => {
            const length = action.payload
            if (length > 0) {
                state.user_friendlist_status = 'idle'
                state.user_friendlist_page += 1
            } else state.user_friendlist_status = 'done'
        },
        [getLikes.rejected]: state => {
            state.post_likes_status = 'error'
        },
        [getLikes.pending]: state => {
            state.post_likes_status = 'loading'
        },
        [getLikes.fulfilled]: (state, action) => {
            const length = action.payload
            if (length > 0) {
                state.post_likes_status = 'idle'
                state.post_likes_page += 1
            } else state.post_likes_status = 'done'
        },

        [getReposts.rejected]: state => {
            state.post_reposts_status = 'error'
        },
        [getReposts.pending]: state => {
            state.post_reposts_status = 'loading'
        },
        [getReposts.fulfilled]: (state, action) => {
            const length = action.payload
            if (length > 0) {
                state.post_reposts_status = 'idle'
                state.post_reposts_page += 1
            } else state.post_reposts_status = 'done'
        },
    },
})
const { actions, reducer } = usersSlice
export default reducer
export const {
    followingChanged,
    userAdded,
    usersAdded,
    resetTimelinePage,
    resetFollowerlistPage,
    resetFriendlistPage,
    usersAddedDontUpdate,
    resetLikesPage,
    resetRepostsPage,
} = actions

export const usersSelectors = usersAdapter.getSelectors(state => state.users)

export const selectSuggests = createSelector(usersSelectors.selectAll, users =>
    users.filter(user => user.following === false || user.new === true).sort(usersComparer)
)

export const selectSearchUsers = createSelector(
    [usersSelectors.selectAll, (state, query) => query],
    (users, query) => users.filter(user => user.searched === true && user.query === query)
)

export const selectFriends = createSelector(
    [usersSelectors.selectAll, (_, username) => username],
    (users, username) =>
        users
            .filter(user => user.friend_of === username)
            .filter(user => user.friend_of !== user.screen_name)
)
export const selectFollowers = createSelector(
    [usersSelectors.selectAll, (_, username) => username],
    (users, username) =>
        users
            .filter(user => user.follower_of === username)
            .filter(user => user.follower_of !== user.screen_name)
)
export const selectLikes = createSelector(
    [usersSelectors.selectAll, (_, postId) => postId],
    (users, postId) => users.filter(user => user.liked_post === postId)
)
export const selectReposts = createSelector(
    [usersSelectors.selectAll, (_, postId) => postId],
    (users, postId) => users.filter(user => user.reposted_post === postId)
)

// export { selectUserPosts } from 'features/posts/postsSlice'