import { createSlice, createAsyncThunk, createAction } from '@reduxjs/toolkit';
import axios from 'axios';
import jwt from 'jsonwebtoken';

interface MainState {
  isFetching: boolean;
  isRequestingOtp: boolean;
  errorMessage: string;
  currentUser: any;
  notify: any;
  token: string;
}

const initialState: MainState = {
  /* User */
  isFetching: false,
  isRequestingOtp: false,
  errorMessage: '',
  currentUser: null,
  token: '',
  notify: {
    showNotification: false,
    textNotification: '',
    typeNotification: 'warn',
  },
};

export const resetAction = createAction('auth/passwordReset/reset')
export const setAuthToken = createAction<string>('auth/setAuthToken')

export const loginUser = createAsyncThunk(
    'auth/loginUser',
    async (creds: Record<string, string>, { rejectWithValue }) => {
      try {
        const response = await axios.post('auth/signin/local', creds);
        return response.data;
      } catch (error) {
        if (!error.response) {
          throw error;
        }
        return rejectWithValue(error.response.data);
      }
    }
);

export const requestEmailOtp = createAsyncThunk(
    'auth/requestEmailOtp',
    async (payload: { email: string }, { rejectWithValue }) => {
      try {
        const response = await axios.post('/auth/otp/request', payload);
        return response.data;
      } catch (error) {
        if (!error.response) {
          throw error;
        }
        return rejectWithValue(error.response.data);
      }
    }
);

export const verifyEmailOtp = createAsyncThunk(
    'auth/verifyEmailOtp',
    async (payload: { email: string; otp: string }, { rejectWithValue }) => {
      try {
        const response = await axios.post('/auth/otp/verify', payload);
        return response.data;
      } catch (error) {
        if (!error.response) {
          throw error;
        }
        return rejectWithValue(error.response.data);
      }
    }
);

export const passwordReset = createAsyncThunk(
    'auth/passwordReset',
    async (value: Record<string, string>, { rejectWithValue }) => {
      try {
        const { data: response } = await axios.put('/auth/password-reset', {
          token: value.token,
          password: value.password,
          type: value.type,
        });

        return response.data;
      } catch (error) {
        if (!error.response) {
          throw error;
        }

        return rejectWithValue(error.response.data);
      }
    },
);

export const findMe = createAsyncThunk('auth/findMe', async () => {
  const response = await axios.get('auth/me');
  return response.data;
});

const persistAuthToken = (state: MainState, token: string) => {
  const user = jwt.decode(token);

  state.errorMessage = '';
  state.token = token;
  state.isFetching = false;
  localStorage.setItem('token', token);
  localStorage.setItem('user', JSON.stringify(user));
  axios.defaults.headers.common['Authorization'] = 'Bearer ' + token;
};

export const authSlice = createSlice({
  name: 'auth',
  initialState,
  reducers: {
    logoutUser: (state) => {
      localStorage.removeItem('token');
      localStorage.removeItem('user');
      axios.defaults.headers.common['Authorization'] = '';
      state.currentUser = null;
      state.token = '';
    },
  },
  extraReducers: (builder) => {
    builder.addCase(loginUser.pending, (state) => {
      state.isFetching = true;
    });
    builder.addCase(loginUser.fulfilled, (state, action) => {
      persistAuthToken(state, action.payload);
    });

    builder.addCase(loginUser.rejected, (state, action) => {
      state.errorMessage = String(action.payload) || 'Something went wrong. Try again';
      state.isFetching = false;
    });

    builder.addCase(requestEmailOtp.pending, (state) => {
      state.isRequestingOtp = true;
      state.errorMessage = '';
    });
    builder.addCase(requestEmailOtp.fulfilled, (state) => {
      state.isRequestingOtp = false;
      state.errorMessage = '';
    });
    builder.addCase(requestEmailOtp.rejected, (state, action) => {
      state.errorMessage = String(action.payload) || 'Failed to send OTP';
      state.isRequestingOtp = false;
    });

    builder.addCase(verifyEmailOtp.pending, (state) => {
      state.isFetching = true;
      state.errorMessage = '';
    });
    builder.addCase(verifyEmailOtp.fulfilled, (state, action) => {
      persistAuthToken(state, action.payload);
    });
    builder.addCase(verifyEmailOtp.rejected, (state, action) => {
      state.errorMessage = String(action.payload) || 'Failed to verify OTP';
      state.isFetching = false;
    });

    builder.addCase(setAuthToken, (state, action) => {
      persistAuthToken(state, action.payload);
    });
    builder.addCase(findMe.pending, () => {
      console.log('Pending findMe');
    });
    builder.addCase(findMe.fulfilled, (state, action) => {
      state.currentUser = action.payload;
      state.isFetching = false;
    });

    builder.addCase(passwordReset.fulfilled, (state, action) => {
      state.notify.showNotification = true;
      state.notify.textNotification = 'Password has been reset successfully';
    });

    builder.addCase(resetAction, (state) => initialState);

    builder.addCase(passwordReset.rejected, (state) => {
      state.errorMessage = 'Something was wrong. Try again';
    });
  },
});

// Action creators are generated for each case reducer function
export const { logoutUser } = authSlice.actions;

export default authSlice.reducer;
