import { RejectedActionPayload, ServerErrorResponse } from '@/interface/Shared';
import {
  TrainingSession,
  CreateTrainingSessionPayload,
  UpdateTrainingSessionPayload,
  DeleteTrainingSessionPayload,
  SessionCapacity,
  CancelSessionPayload,
} from '@/interface/Training';
import Helpers from '@/utilities/Helpers';
import { createAsyncThunk, createSlice, Draft, PayloadAction } from '@reduxjs/toolkit';
import { message } from 'antd';
import { TrainingSessionsActions } from './actionTypes';
import { apiDelete, apiGet, apiPost, apiPut } from '@/services/api/api';
import axios, { AxiosResponse } from 'axios';

interface TrainingSessionState {
  sessions: TrainingSession[];
  selectedSession: TrainingSession | null;
  capacity: SessionCapacity | null;
  availableSessions: TrainingSession[];
  meta: {
    current_page: number;
    last_page: number;
    per_page: number;
    total: number;
  } | null;
  loading: boolean;
  error: string | null;
}

const initialState: TrainingSessionState = {
  sessions: [],
  selectedSession: null,
  capacity: null,
  availableSessions: [],
  meta: null,
  loading: false,
  error: null,
};

export const fetchTrainingSessions = createAsyncThunk(
  TrainingSessionsActions.FETCH_TRAINING_SESSIONS_REQUEST,
  async (params?: {
    status?: string;
    program_id?: string;
    branch_id?: string;
    from_date?: string;
    to_date?: string;
    search?: string;
    per_page?: number;
  }) => {
    const queryParams = new URLSearchParams();
    if (params?.status) queryParams.append('status', params.status);
    if (params?.program_id) queryParams.append('program_id', params.program_id);
    if (params?.branch_id) queryParams.append('branch_id', params.branch_id);
    if (params?.from_date) queryParams.append('from_date', params.from_date);
    if (params?.to_date) queryParams.append('to_date', params.to_date);
    if (params?.search) queryParams.append('search', params.search);
    if (params?.per_page) queryParams.append('per_page', String(params.per_page));
    const query = queryParams.toString() ? `?${queryParams.toString()}` : '';
    const response = (await apiGet(`/training/sessions${query}`)) as AxiosResponse<
      TrainingSession[]
    >;
    return response.data;
  },
);

export const fetchSession = createAsyncThunk(
  TrainingSessionsActions.FETCH_SESSION_REQUEST,
  async (id: string) => {
    const response = (await apiGet(
      `/training/sessions/${id}`,
    )) as AxiosResponse<TrainingSession>;
    return response.data;
  },
);

export const createTrainingSession = createAsyncThunk(
  TrainingSessionsActions.CREATE_TRAINING_SESSION_REQUEST,
  async (payload: CreateTrainingSessionPayload, { rejectWithValue }) => {
    try {
      const response = (await apiPost(
        '/training/sessions',
        payload,
      )) as AxiosResponse<{ data: TrainingSession }>;
      return response.data.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const updateTrainingSession = createAsyncThunk(
  TrainingSessionsActions.UPDATE_TRAINING_SESSION_REQUEST,
  async (payload: UpdateTrainingSessionPayload, { rejectWithValue }) => {
    try {
      const { id, ...data } = payload;
      const response = (await apiPut(
        `/training/sessions/${id}`,
        data,
      )) as AxiosResponse<{ data: TrainingSession }>;
      return response.data.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const deleteTrainingSession = createAsyncThunk(
  TrainingSessionsActions.DELETE_TRAINING_SESSION_REQUEST,
  async (id: string, { rejectWithValue }) => {
    try {
      const response = (await apiDelete(
        `/training/sessions/${id}`,
      )) as AxiosResponse<DeleteTrainingSessionPayload>;
      const responseData = response.data;
      responseData.id = id;
      return responseData;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const openEnrollment = createAsyncThunk(
  TrainingSessionsActions.OPEN_ENROLLMENT_REQUEST,
  async (id: string, { rejectWithValue }) => {
    try {
      const response = (await apiPost(
        `/training/sessions/${id}/open-enrollment`,
        {},
      )) as AxiosResponse<{ data: TrainingSession }>;
      return response.data.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const startSession = createAsyncThunk(
  TrainingSessionsActions.START_SESSION_REQUEST,
  async (id: string, { rejectWithValue }) => {
    try {
      const response = (await apiPost(
        `/training/sessions/${id}/start`,
        {},
      )) as AxiosResponse<{ data: TrainingSession }>;
      return response.data.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const completeSession = createAsyncThunk(
  TrainingSessionsActions.COMPLETE_SESSION_REQUEST,
  async (id: string, { rejectWithValue }) => {
    try {
      const response = (await apiPost(
        `/training/sessions/${id}/complete`,
        {},
      )) as AxiosResponse<{ data: TrainingSession }>;
      return response.data.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const cancelSession = createAsyncThunk(
  TrainingSessionsActions.CANCEL_SESSION_REQUEST,
  async (payload: CancelSessionPayload, { rejectWithValue }) => {
    try {
      const { id, ...data } = payload;
      const response = (await apiPost(
        `/training/sessions/${id}/cancel`,
        data,
      )) as AxiosResponse<{ data: TrainingSession }>;
      return response.data.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const fetchCapacity = createAsyncThunk(
  TrainingSessionsActions.FETCH_CAPACITY_REQUEST,
  async (id: string) => {
    const response = (await apiGet(
      `/training/sessions/${id}/capacity`,
    )) as AxiosResponse<SessionCapacity>;
    return response.data;
  },
);

export const fetchAvailableSessions = createAsyncThunk(
  TrainingSessionsActions.FETCH_AVAILABLE_SESSIONS_REQUEST,
  async () => {
    const response = (await apiGet(
      '/training/sessions/available',
    )) as AxiosResponse<TrainingSession[]>;
    return response.data;
  },
);

const updateSessionInArray = (
  state: Draft<TrainingSessionState>,
  session: TrainingSession,
) => {
  const index = state.sessions.findIndex((s) => s.id === session.id);
  if (index !== -1) state.sessions[index] = session;
  if (state.selectedSession?.id === session.id) {
    state.selectedSession = session;
  }
};

export const TrainingSessionsSlice = createSlice({
  name: 'trainingSessions',
  initialState,
  reducers: {
    clearSelectedSession(state) {
      state.selectedSession = null;
      state.capacity = null;
    },
  },
  extraReducers(builder) {
    builder
      .addCase(fetchTrainingSessions.pending, (state: Draft<TrainingSessionState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(
        fetchTrainingSessions.fulfilled,
        (state: Draft<TrainingSessionState>, action: PayloadAction<TrainingSession[]>) => {
          state.sessions = action.payload;
          state.error = null;
          state.loading = false;
        },
      )
      .addCase(fetchTrainingSessions.rejected, (state: Draft<TrainingSessionState>, action: RejectedActionPayload) => {
        state.loading = false;
        state.error = 'Failed to load training sessions';
        message.error(Helpers.handleServerError(action.payload), 8);
      });

    builder
      .addCase(fetchSession.pending, (state: Draft<TrainingSessionState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(
        fetchSession.fulfilled,
        (state: Draft<TrainingSessionState>, action: PayloadAction<TrainingSession>) => {
          state.selectedSession = action.payload;
          state.error = null;
          state.loading = false;
        },
      )
      .addCase(fetchSession.rejected, (state: Draft<TrainingSessionState>, action: RejectedActionPayload) => {
        state.loading = false;
        state.error = 'Failed to load session details';
        message.error(Helpers.handleServerError(action.payload), 8);
      });

    builder
      .addCase(createTrainingSession.pending, (state: Draft<TrainingSessionState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(
        createTrainingSession.fulfilled,
        (state: Draft<TrainingSessionState>, action: PayloadAction<TrainingSession>) => {
          state.sessions.unshift(action.payload);
          state.error = null;
          state.loading = false;
          message.success('Training session created successfully');
        },
      )
      .addCase(
        createTrainingSession.rejected,
        (state: Draft<TrainingSessionState>, action: RejectedActionPayload) => {
          state.loading = false;
          state.error = Helpers.handleServerError(action.payload);
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );

    builder
      .addCase(updateTrainingSession.pending, (state: Draft<TrainingSessionState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(
        updateTrainingSession.fulfilled,
        (state: Draft<TrainingSessionState>, action: PayloadAction<TrainingSession>) => {
          updateSessionInArray(state, action.payload);
          state.loading = false;
          state.error = null;
          message.success('Training session updated successfully');
        },
      )
      .addCase(
        updateTrainingSession.rejected,
        (state: Draft<TrainingSessionState>, action: RejectedActionPayload) => {
          state.loading = false;
          state.error = Helpers.handleServerError(action.payload);
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );

    builder
      .addCase(deleteTrainingSession.pending, (state: Draft<TrainingSessionState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(
        deleteTrainingSession.fulfilled,
        (
          state: Draft<TrainingSessionState>,
          action: PayloadAction<DeleteTrainingSessionPayload>,
        ) => {
          state.sessions = state.sessions.filter((s) => s.id !== action.payload.id);
          if (state.selectedSession?.id === action.payload.id) {
            state.selectedSession = null;
            state.capacity = null;
          }
          state.loading = false;
          message.success(action.payload.message);
        },
      )
      .addCase(
        deleteTrainingSession.rejected,
        (state: Draft<TrainingSessionState>, action: RejectedActionPayload) => {
          state.loading = false;
          state.error = Helpers.handleServerError(action.payload);
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );

    builder
      .addCase(openEnrollment.pending, (state: Draft<TrainingSessionState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(
        openEnrollment.fulfilled,
        (state: Draft<TrainingSessionState>, action: PayloadAction<TrainingSession>) => {
          updateSessionInArray(state, action.payload);
          state.loading = false;
          state.error = null;
          message.success('Enrollment opened successfully');
        },
      )
      .addCase(
        openEnrollment.rejected,
        (state: Draft<TrainingSessionState>, action: RejectedActionPayload) => {
          state.loading = false;
          state.error = Helpers.handleServerError(action.payload);
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );

    builder
      .addCase(startSession.pending, (state: Draft<TrainingSessionState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(
        startSession.fulfilled,
        (state: Draft<TrainingSessionState>, action: PayloadAction<TrainingSession>) => {
          updateSessionInArray(state, action.payload);
          state.loading = false;
          state.error = null;
          message.success('Session started successfully');
        },
      )
      .addCase(
        startSession.rejected,
        (state: Draft<TrainingSessionState>, action: RejectedActionPayload) => {
          state.loading = false;
          state.error = Helpers.handleServerError(action.payload);
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );

    builder
      .addCase(completeSession.pending, (state: Draft<TrainingSessionState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(
        completeSession.fulfilled,
        (state: Draft<TrainingSessionState>, action: PayloadAction<TrainingSession>) => {
          updateSessionInArray(state, action.payload);
          state.loading = false;
          state.error = null;
          message.success('Session completed successfully');
        },
      )
      .addCase(
        completeSession.rejected,
        (state: Draft<TrainingSessionState>, action: RejectedActionPayload) => {
          state.loading = false;
          state.error = Helpers.handleServerError(action.payload);
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );

    builder
      .addCase(cancelSession.pending, (state: Draft<TrainingSessionState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(
        cancelSession.fulfilled,
        (state: Draft<TrainingSessionState>, action: PayloadAction<TrainingSession>) => {
          updateSessionInArray(state, action.payload);
          state.loading = false;
          state.error = null;
          message.success('Session cancelled successfully');
        },
      )
      .addCase(
        cancelSession.rejected,
        (state: Draft<TrainingSessionState>, action: RejectedActionPayload) => {
          state.loading = false;
          state.error = Helpers.handleServerError(action.payload);
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );

    builder
      .addCase(fetchCapacity.pending, (state: Draft<TrainingSessionState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(
        fetchCapacity.fulfilled,
        (state: Draft<TrainingSessionState>, action: PayloadAction<SessionCapacity>) => {
          state.capacity = action.payload;
          state.loading = false;
          state.error = null;
        },
      )
      .addCase(fetchCapacity.rejected, (state: Draft<TrainingSessionState>, action: RejectedActionPayload) => {
        state.loading = false;
        state.error = 'Failed to load session capacity';
        message.error(Helpers.handleServerError(action.payload), 8);
      });

    builder
      .addCase(fetchAvailableSessions.pending, (state: Draft<TrainingSessionState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(
        fetchAvailableSessions.fulfilled,
        (state: Draft<TrainingSessionState>, action: PayloadAction<TrainingSession[]>) => {
          state.availableSessions = action.payload;
          state.loading = false;
          state.error = null;
        },
      )
      .addCase(fetchAvailableSessions.rejected, (state: Draft<TrainingSessionState>, action: RejectedActionPayload) => {
        state.loading = false;
        state.error = 'Failed to load available sessions';
        message.error(Helpers.handleServerError(action.payload), 8);
      });
  },
});

export const { clearSelectedSession } = TrainingSessionsSlice.actions;
export default TrainingSessionsSlice;
export type { TrainingSessionState };
