import {createSlice, createAsyncThunk, createSelector} from '@reduxjs/toolkit';
import AuthenticationService from 'services/authentication.service';
import {PhenixWebSocketStatusMapping, PhenixWebSocketStatusType} from 'services/net/PhenixWebSocket';

export interface IAuthenticationState {
  applicationId: string | null;
  secret: string | null;
  isAuthenticated: boolean;
  isAuthenticating: boolean;
  error: string | null;
  status: PhenixWebSocketStatusType;
  sessionId: string | null;
  roles: string[];
}

const initialAuthenticationState: IAuthenticationState = {
  applicationId: null,
  secret: null,
  isAuthenticated: false,
  isAuthenticating: false,
  error: null,
  status: 'Offline',
  sessionId: null,
  roles: []
};

// Memoized selectors
export const selectAuthentication = (state: {authentication: IAuthenticationState}) => state.authentication;

export const selectIsAuthenticating = createSelector([selectAuthentication], authentication => authentication.isAuthenticating);

export const selectIsAuthenticated = createSelector([selectAuthentication], authentication => authentication.isAuthenticated);

export const selectError = createSelector([selectAuthentication], authentication => authentication.error);

export const selectStatus = createSelector([selectAuthentication], authentication => authentication.status);

export const selectCredentials = createSelector([selectAuthentication], authentication => ({
  applicationId: authentication.applicationId,
  secret: authentication.secret
}));

export const selectSessionInfo = createSelector([selectAuthentication], authentication => ({
  sessionId: authentication.sessionId,
  roles: authentication.roles
}));

const authenticateCredentialsThunk = createAsyncThunk(
  'authentication/authenticate',
  async (credentials: {applicationId: string; secret: string}, {rejectWithValue}) => {
    return AuthenticationService.authenticateCredentials(credentials.applicationId, credentials.secret).catch(rejectWithValue);
  }
);

const signoutThunk = createAsyncThunk('authentication/signout', async (_, {rejectWithValue}) => {
  return AuthenticationService.signout().catch(rejectWithValue);
});

const authenticationSlice = createSlice({
  name: 'authentication',
  initialState: {...initialAuthenticationState},
  reducers: {
    setStatus: (state, action) => {
      state.status = PhenixWebSocketStatusMapping.convertPhenixWebSocketStatusToPhenixWebSocketStatusType(action.payload);
    },
    signout: state => {
      state.isAuthenticated = false;
      state.isAuthenticating = false;
      state.applicationId = null;
      state.secret = null;
      state.error = null;
      state.sessionId = null;
      state.roles = [];
    },
    error: (state, action) => {
      // Store only the error message string, not the Error object
      if (typeof action.payload === 'string') {
        state.error = action.payload;
      } else if (action.payload instanceof Error) {
        state.error = action.payload.message;
      } else if (action.payload && typeof action.payload === 'object' && 'message' in action.payload) {
        state.error = String((action.payload as {message: unknown}).message);
      } else {
        state.error = action.payload ? String(action.payload) : null;
      }
    }
  },
  extraReducers: builder => {
    builder
      .addCase(authenticateCredentialsThunk.pending, state => {
        state.isAuthenticating = true;
        state.error = null;
      })
      .addCase(authenticateCredentialsThunk.rejected, (state, action) => {
        state.isAuthenticating = false;
        // Extract error message string instead of creating new Error object
        let errorMessage = 'Authentication failed';

        if (action.payload) {
          if (action.payload instanceof Error) {
            errorMessage = action.payload.message;
          } else if (typeof action.payload === 'object' && action.payload !== null && 'message' in action.payload) {
            errorMessage = String((action.payload as {message: unknown}).message);
          } else if (typeof action.payload === 'string') {
            errorMessage = action.payload;
          } else {
            errorMessage = String(action.payload);
          }
        }

        state.error = errorMessage;
        state.isAuthenticated = false;
        state.applicationId = null;
        state.secret = null;
        state.sessionId = null;
        state.roles = [];
      })
      .addCase(authenticateCredentialsThunk.fulfilled, (state, action) => {
        state.isAuthenticating = false;

        if (action.payload.error) {
          state.error = action.payload.error as string;
          state.isAuthenticated = false;
        } else if (action.payload.response && (action.payload.response as {status: string}).status === 'ok') {
          state.isAuthenticated = true;
          

          
          // Safely extract sessionId and roles with type checking
          if (action.payload.response && typeof action.payload.response === 'object') {
            const response = action.payload.response as any;
            if (response.sessionId && typeof response.sessionId === 'string') {
              state.sessionId = response.sessionId;
            }
            if (Array.isArray(response.roles)) {
              state.roles = response.roles;
            }
          }
        } else {
          state.error = 'Authentication failed';
          state.isAuthenticated = false;
        }
      })
      .addCase(signoutThunk.pending, state => {
        state.isAuthenticating = true;
        state.error = null;
      })
      .addCase(signoutThunk.rejected, (state, action) => {
        state.isAuthenticating = false;
        state.error = action.payload as string;
        state.isAuthenticated = false;
        state.applicationId = null;
        state.secret = null;
        state.sessionId = null;
        state.roles = [];
      })
      .addCase(signoutThunk.fulfilled, state => {
        state.isAuthenticated = false;
        state.isAuthenticating = false;
        state.applicationId = null;
        state.secret = null;
        state.sessionId = null;
        state.roles = [];
      });
  }
});

export const {reducer: authenticationReducer, actions: authenticationActions} = authenticationSlice;
export {authenticateCredentialsThunk, signoutThunk};
