import { createAsyncThunk , createSlice , PayloadAction } from "@reduxjs/toolkit";
import axios from 'axios'
import { fireAlert } from "./alert-slice";
// set the const variables for the slice
const ACTION_NAME = 'products'
// slice initial value state
type IinitialState = {
    value : IValueState;
}
// state value type
type IValueState = {
    empty: boolean,
    isLoading: boolean,
    loadedFirstTime: boolean,
    total: number,
    currentPage: number,
    searchKeyword: string,
    listContent: {
        // this is not a const so it get different for each list
        _id: string | null,
        name: string | null,
        description: string | null,
        price: number | null,
        quantity: number | null,
    }[],
    detailsPopUp: boolean,
    detailsPopUpData: {
        _id: string | null,
        name: string | null,
        description: string | null,
        price: number | null,
        quantity: number | null,
    } | null,
    addPopUp: boolean,
    isAdding: boolean,
    updatePopUp: boolean,
    updatePopUpData: {
        _id: string | null,
        name: string | null,
        description: string | null,
        price: number | null,
        quantity: number | null,
    } | null,
    isUpdating: boolean
}
// set the initial state
const initialState = {
    value: {
        empty: true,
        isLoading: false,
        loadedFirstTime: false,
        total: 0,
        currentPage: 1,
        searchKeyword: '',
        listContent: [],
        detailsPopUp: false,
        detailsPopUpData: {
            _id: null,
            name: null,
            description: null,
            price: null,
            quantity: null,
        },
        addPopUp: false,
        isAdding: false,
        updatePopUp: false,
        updatePopUpData: {
            _id: null,
            name: null,
            description: null,
            price: null,
            quantity: null,
        },
        isUpdating: false
    }
} as IinitialState
// thunks
// add ability
const add = createAsyncThunk(
    'products/add',
    async (actionPayload : {
        name: string,
        description: string,
        price : number,
        quantity: number,
    } , thunkAPI) => {
        try{

            let { data } = await axios.post(`/api/user/actions/${ACTION_NAME}` , {
               payload:actionPayload
            })
            if(data.success)
            {
                thunkAPI.dispatch(fireAlert({ 
                    success: true,
                    message: "actionDoneWithSuccess",
                }))
                return data
            }
            else {
                thunkAPI.dispatch(fireAlert({
                    success: false,
                    message: data.message
                }))
                return { success : false }
            }
        }catch(e)
        {
            thunkAPI.dispatch(fireAlert({
                success: false,
                message: "unkownError",
            }))
            return { success : false }
        }
    }
)
// load data ability
const load = createAsyncThunk(
    'products/load',
    async (actionPayload : { page : number }, thunkAPI) => {
        try {
            let { data } = await axios.get(`/api/user/actions/${ACTION_NAME}?type=page&page=`+actionPayload.page)
            if(data.success)
            {
                return data
            }
            else 
            {
                return { success : false }
            }
        }catch(err) {
            return { success : false }
        }
    }
)
// search ability
const search = createAsyncThunk(
    'products/search',
    async (actionPayload : {searchKeyword: string}, thunkAPI) => {
        try {
            let { data } = await axios.get(`/api/user/actions/${ACTION_NAME}?type=search&searchKeyword=`+actionPayload.searchKeyword)
            if(data.success)
            {
                return data
            }
            else 
            {                
                thunkAPI.dispatch(fireAlert({ 
                    success: false,
                    message: data.message,
                }))
                return { success : false }
            }
        }catch(err) {
            return { success : false }
        }
    }
)
// delete ability
const delete_ = createAsyncThunk(
    'products/delete',
    async (actionPayload : {id: string | null}, thunkAPI) => {
        const state : any = thunkAPI.getState()
        try {
            let { data } = await axios.delete(`/api/user/actions/${ACTION_NAME}?_id=${actionPayload.id}&page=${state.servicesReducer.value.currentPage}`)
            if(data.success)
            {
                thunkAPI.dispatch(fireAlert({ 
                    success: true,
                    message: "actionDoneWithSuccess",
                }))
                return {
                    success: true,
                    id: actionPayload.id,
                    data: data.data
                }
            }
            else 
            {
                return { success : false }
            }
        }catch(err) {
            return { success : false }
        }
    }
)
// update ability
const update = createAsyncThunk(
    'products/update',
    async (actionPayload : {
        _id: string | null | undefined,
        name: string | null | undefined,
        description: string | null | undefined,
        price : number | null | undefined,
        quantity: number | null | undefined,
    }, thunkAPI) => {
        try {
            let { data } = await axios.put(`/api/user/actions/${ACTION_NAME}`, {
                payload: actionPayload
            })
            if(data.success)
            {
                thunkAPI.dispatch(fireAlert({ 
                    success: true,
                    message: "actionDoneWithSuccess",
                }))
                return data
            }
            else 
            {
                return { success : false }
            }
        }catch(err) {
            return { success : false }
        }
    }
)
// init the slice
export const services = createSlice({
    name: ACTION_NAME,
    initialState,
    reducers: {
        // set the current list page
        setCurrentPage: (state , action: PayloadAction<number>) => {
            state.value.currentPage = action.payload
        },
        // set the list search keyword
        setSearchKeyword : (state , action : PayloadAction<string>) => {
            state.value.searchKeyword = action.payload
        },
        // set the details popup status
        setDetailsPopUp: (state , action : PayloadAction<{
            status: boolean,
            data: {
                _id: string | null,
                name: string |  null,
                description: string |  null,
                price: number |  null,
                quantity: number | null,
            } | null
        }>) => {
            state.value.detailsPopUp = action.payload.status
            if(action.payload.data)
            {
                state.value.detailsPopUpData = action.payload.data
            }
        },
        // set the add popup status
        setAddPopUp: (state , action : PayloadAction<boolean>) => {
            state.value.addPopUp = action.payload
        },
        // set the update popup status
        setUpdatePopUp: (state , action : PayloadAction<{
            status: boolean,
            data: {
                _id: string | null,
                name: string | null,
                description: string | null,
                price: number | null,
                quantity: number | null,
            } | null
        }>) => {
            state.value.updatePopUp = action.payload.status
            if(action.payload.data)
            {
                state.value.updatePopUpData = action.payload.data
            }
        }
    },
    extraReducers: (builder) => {
        // add ability
        builder.addCase(add.pending, (state : IinitialState , action) => {
            state.value.isAdding = true
        })
        builder.addCase(add.fulfilled, (state : IinitialState , action) => {
            if(action.payload.success) state.value.listContent.push(action.payload.data)
            state.value.isAdding = false
        })
        // load ability
        builder.addCase(load.pending, (state : IinitialState , action) => {
            state.value.isLoading = true;
        })
        builder.addCase(load.fulfilled, (state : IinitialState , action) => {
            if(action.payload.success) {
                state.value.listContent = action.payload.data.docs
                state.value.isLoading = false;
                state.value.loadedFirstTime = true;
                state.value.total = action.payload.data.docs_count
            }
        })
        // search ability
        builder.addCase(search.pending, (state : IinitialState , action) => {
            state.value.isLoading = true;
        })
        builder.addCase(search.fulfilled, (state : IinitialState , action) => {
            if(action.payload.success) {
                state.value.listContent = action.payload.data.docs
                state.value.total = action.payload.data.docs_count
            }
            state.value.isLoading = false;
        })
        // delete ability
        builder.addCase(delete_.pending, (state : IinitialState , action) => {
            state.value.isLoading = true;
        })
        builder.addCase(delete_.fulfilled, (state : IinitialState , action) => {
            state.value.isLoading = false;
            if(action.payload.success)
            {                
                state.value.listContent = action.payload.data.docs
                state.value.total = action.payload.data.docs_count
                if(Math.ceil(action.payload.data.totalArrLength / 4) < state.value.currentPage)
                {
                    state.value.currentPage -= 1
                }
            }
        })
        // update ability
        builder.addCase(update.pending, (state : IinitialState , action) => {
            state.value.isUpdating = true;
        })
        builder.addCase(update.fulfilled, (state : IinitialState , action) => {
            state.value.isUpdating = false;
            // update the obj in the ui
            // first we get the obj index
            const indexOfObjectToUpdate = state.value.listContent.findIndex(obj => obj._id === action.payload.data._id);
            // we copie the list content
            const updatedObjects = [...state.value.listContent];
            // we update the obj in the list copie
            updatedObjects[indexOfObjectToUpdate] = action.payload.data;
            // we set the original list value to the copie
            state.value.listContent = updatedObjects
        })
    }
})
// export reducers
export const { setCurrentPage , setSearchKeyword , setDetailsPopUp , setAddPopUp , setUpdatePopUp } = services.actions;
// export extra reducers
export { add , load , search , delete_ , update }
// export the slice
export default services.reducer;