/**
 *
 * @description Auth system state handler
 * * source : https://redux-toolkit.js.org/api/createslice
 * *          https://redux-toolkit.js.org/api/createAsyncThunk
 */

import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
import axios from 'axios'
import Cookies from 'universal-cookie';
import { fireAlert } from './alert-slice';

const cookies = new Cookies();

type IinitialState = {
    value: AuthState;
}

type AuthState = {
    authToken: string | null;
    isValid: boolean | null;
    checkIfValidMounted: boolean;
}

const initialState = {
    value: {
        // try to get the token from the browser cookies
        authToken: cookies.get("authToken") || null,
        isValid: null,
        checkIfValidMounted: false,
    }
} as IinitialState

const logIn = createAsyncThunk(
    'auth/logInStatus',
    async (actionPayload: { username: string, password: string, successCallback: any }, thunkAPI) => {
        try {
            let { data } = await axios.post('/api/auth', actionPayload)
            if (data.success) {
                actionPayload.successCallback()
                // fire the success alert
                thunkAPI.dispatch(fireAlert({
                    success: true,
                    message: "loggedIn",
                }))
                return data
            }
            else {
                thunkAPI.dispatch(fireAlert({
                    success: false,
                    message: data.message
                }))
                return { success: false }
            }
        } catch (err) {
            thunkAPI.dispatch(fireAlert({
                success: false,
                message: "unkownError",
            }))
            return { success: false }
        }
    }
)

const isLoggedIn = createAsyncThunk(
    'auth/isLoggedInStatus',
    async (actionPayload: { LoggedInCallback?: () => void; NotLoggedInCallback?: () => void }, { dispatch, getState }) => {
        try {
            const state = getState() as RootState;
            const { authToken } = state.authReducer.value;

            // If no token, immediately trigger not logged in
            if (!authToken) {
                if (actionPayload.NotLoggedInCallback) {
                    actionPayload.NotLoggedInCallback();
                }
                return { isValid: false };
            }

            try {
                const { data } = await axios.get('/api/auth?authToken=' + authToken);

                if (!data.success) {
                    // If token is invalid or expired, clear it
                    if (data.message === 'expiredToken' || data.message === 'invalidToken') {
                        dispatch(logOut());
                        document.cookie = 'authToken=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
                    }

                    if (actionPayload.NotLoggedInCallback) {
                        actionPayload.NotLoggedInCallback();
                    }
                } else if (actionPayload.LoggedInCallback) {
                    actionPayload.LoggedInCallback();
                }

                return { isValid: data.success };
            } catch (error: any) {
                // Handle network errors or server issues
                console.error('Token validation error:', error);

                // If it's an auth-related error, clear the token
                if (error.response?.status === 401 || error.response?.data?.message === 'expiredToken') {
                    dispatch(logOut());
                    document.cookie = 'authToken=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
                }

                if (actionPayload.NotLoggedInCallback) {
                    actionPayload.NotLoggedInCallback();
                }

                return { isValid: false };
            }
        } catch (error) {
            console.error('Error in isLoggedIn:', error);
            if (actionPayload.NotLoggedInCallback) {
                actionPayload.NotLoggedInCallback();
            }
            return { isValid: false };
        }
    }
)

export const auth = createSlice({
    name: "auth",
    initialState,
    reducers: {
        logOut: (state) => {
            // remove the authToken cookie
            cookies.remove('authToken', { path: '/' });
            // reset the state to there initial value
            state.value.isValid = null
            state.value.authToken = null
        },
        mountCheckIfValid: (state) => {
            state.value.checkIfValidMounted = true
        },
    },
    extraReducers: (builder) => {
        // logIn thunk reducer
        builder.addCase(logIn.fulfilled, (state: IinitialState, action) => {
            // set the state
            if (action.payload.success) {
                state.value.authToken = action.payload.authToken;
                state.value.isValid = true
            }
        })
        // check if user authToken cookie is a valid one
        builder.addCase(isLoggedIn.fulfilled, (state: IinitialState, action) => {
            // set the state
            state.value.isValid = action.payload.isValid;
            state.value.checkIfValidMounted = true
        })
    },
})

// export the functions
export const { logOut, mountCheckIfValid } = auth.actions;
export { logIn, isLoggedIn };
export default auth.reducer;