import { RejectedActionPayload, ServerErrorResponse } from '@/interface/Shared';
import { RecruitmentApprovalInstance } from '@/interface/Recruitment';
import Helpers from '@/utilities/Helpers';
import { createAsyncThunk, createSlice, Draft, PayloadAction } from '@reduxjs/toolkit';
import { message } from 'antd';
import axios, { AxiosResponse } from 'axios';
import { apiGet, apiPost } from '@/services/api/api';
import { RecruitmentApprovalsActions } from './actionTypes';

interface RecruitmentApprovalsState {
  pendingApprovals: RecruitmentApprovalInstance[];
  approvalInstance: RecruitmentApprovalInstance | null;
  history: any[];
  loading: boolean;
  actionLoading: boolean;
  error: string | null;
}

const initialState: RecruitmentApprovalsState = {
  pendingApprovals: [],
  approvalInstance: null,
  history: [],
  loading: false,
  actionLoading: false,
  error: null,
};

export const fetchPendingRecruitmentApprovals = createAsyncThunk(
  RecruitmentApprovalsActions.FETCH_PENDING,
  async (_: void, { rejectWithValue }) => {
    try {
      const response = (await apiGet('/recruitment/approvals/pending')) as AxiosResponse<{
        data: RecruitmentApprovalInstance[];
      }>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const fetchApprovalInstance = createAsyncThunk(
  RecruitmentApprovalsActions.FETCH_INSTANCE,
  async (instanceId: string, { rejectWithValue }) => {
    try {
      const response = (await apiGet(
        `/recruitment/approvals/${instanceId}`,
      )) as AxiosResponse<{ data: RecruitmentApprovalInstance }>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const fetchApprovalHistory = createAsyncThunk(
  RecruitmentApprovalsActions.FETCH_HISTORY,
  async (
    { entityType, entityId }: { entityType: string; entityId: string },
    { rejectWithValue },
  ) => {
    try {
      const response = (await apiGet(
        `/recruitment/approvals/history/${entityType}/${entityId}`,
      )) as AxiosResponse<{ data: any[] }>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const approveRecruitmentInstance = createAsyncThunk(
  RecruitmentApprovalsActions.APPROVE,
  async ({ instanceId, notes }: { instanceId: string; notes?: string }, { rejectWithValue }) => {
    try {
      const response = (await apiPost(`/recruitment/approvals/${instanceId}/approve`, {
        notes,
      })) as AxiosResponse<{ data: RecruitmentApprovalInstance }>;
      return { ...response.data, instanceId };
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const rejectRecruitmentInstance = createAsyncThunk(
  RecruitmentApprovalsActions.REJECT,
  async ({ instanceId, notes }: { instanceId: string; notes: string }, { rejectWithValue }) => {
    try {
      const response = (await apiPost(`/recruitment/approvals/${instanceId}/reject`, {
        notes,
      })) as AxiosResponse<{ data: RecruitmentApprovalInstance }>;
      return { ...response.data, instanceId };
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const sendBackRecruitmentInstance = createAsyncThunk(
  RecruitmentApprovalsActions.SEND_BACK,
  async ({ instanceId, notes }: { instanceId: string; notes: string }, { rejectWithValue }) => {
    try {
      const response = (await apiPost(`/recruitment/approvals/${instanceId}/send-back`, {
        notes,
      })) as AxiosResponse<{ data: RecruitmentApprovalInstance }>;
      return { ...response.data, instanceId };
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const delegateRecruitmentApproval = createAsyncThunk(
  RecruitmentApprovalsActions.DELEGATE,
  async (
    {
      instanceId,
      delegate_to,
      notes,
    }: { instanceId: string; delegate_to: string; notes?: string },
    { rejectWithValue },
  ) => {
    try {
      const response = (await apiPost(`/recruitment/approvals/${instanceId}/delegate`, {
        delegate_to,
        notes,
      })) as AxiosResponse<{ data: RecruitmentApprovalInstance }>;
      return { ...response.data, instanceId };
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const cancelRecruitmentWorkflow = createAsyncThunk(
  RecruitmentApprovalsActions.CANCEL,
  async (
    { instanceId, notes }: { instanceId: string; notes?: string },
    { rejectWithValue },
  ) => {
    try {
      const response = (await apiPost(`/recruitment/approvals/${instanceId}/cancel`, {
        notes,
      })) as AxiosResponse<{ data: RecruitmentApprovalInstance }>;
      return { ...response.data, instanceId };
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const RecruitmentApprovalsSlice = createSlice({
  name: 'recruitmentApprovals',
  initialState,
  reducers: {},
  extraReducers(builder) {
    builder
      .addCase(fetchPendingRecruitmentApprovals.pending, (state: Draft<RecruitmentApprovalsState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(
        fetchPendingRecruitmentApprovals.fulfilled,
        (
          state: Draft<RecruitmentApprovalsState>,
          action: PayloadAction<{ data: RecruitmentApprovalInstance[] }>,
        ) => {
          state.pendingApprovals = action.payload.data;
          state.loading = false;
          state.error = null;
        },
      )
      .addCase(
        fetchPendingRecruitmentApprovals.rejected,
        (state: Draft<RecruitmentApprovalsState>, action: RejectedActionPayload) => {
          state.loading = false;
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );

    builder
      .addCase(fetchApprovalInstance.pending, (state: Draft<RecruitmentApprovalsState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(
        fetchApprovalInstance.fulfilled,
        (
          state: Draft<RecruitmentApprovalsState>,
          action: PayloadAction<{ data: RecruitmentApprovalInstance }>,
        ) => {
          state.approvalInstance = action.payload.data;
          state.loading = false;
          state.error = null;
        },
      )
      .addCase(fetchApprovalInstance.rejected, (state: Draft<RecruitmentApprovalsState>) => {
        state.loading = false;
      });

    builder
      .addCase(fetchApprovalHistory.pending, (state: Draft<RecruitmentApprovalsState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(
        fetchApprovalHistory.fulfilled,
        (state: Draft<RecruitmentApprovalsState>, action: PayloadAction<{ data: any[] }>) => {
          state.history = action.payload.data;
          state.loading = false;
          state.error = null;
        },
      )
      .addCase(fetchApprovalHistory.rejected, (state: Draft<RecruitmentApprovalsState>) => {
        state.loading = false;
      });

    const removeFromPending = (
      state: Draft<RecruitmentApprovalsState>,
      instanceId: string,
    ) => {
      state.pendingApprovals = state.pendingApprovals.filter((a) => a.id !== instanceId);
    };

    builder
      .addCase(approveRecruitmentInstance.pending, (state: Draft<RecruitmentApprovalsState>) => {
        state.actionLoading = true;
        state.error = null;
      })
      .addCase(
        approveRecruitmentInstance.fulfilled,
        (
          state: Draft<RecruitmentApprovalsState>,
          action: PayloadAction<{ data: RecruitmentApprovalInstance; instanceId: string }>,
        ) => {
          removeFromPending(state, action.payload.instanceId);
          state.actionLoading = false;
          state.error = null;
        },
      )
      .addCase(
        approveRecruitmentInstance.rejected,
        (state: Draft<RecruitmentApprovalsState>, action: RejectedActionPayload) => {
          state.actionLoading = false;
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );

    builder
      .addCase(rejectRecruitmentInstance.pending, (state: Draft<RecruitmentApprovalsState>) => {
        state.actionLoading = true;
        state.error = null;
      })
      .addCase(
        rejectRecruitmentInstance.fulfilled,
        (
          state: Draft<RecruitmentApprovalsState>,
          action: PayloadAction<{ data: RecruitmentApprovalInstance; instanceId: string }>,
        ) => {
          removeFromPending(state, action.payload.instanceId);
          state.actionLoading = false;
          state.error = null;
        },
      )
      .addCase(
        rejectRecruitmentInstance.rejected,
        (state: Draft<RecruitmentApprovalsState>, action: RejectedActionPayload) => {
          state.actionLoading = false;
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );

    builder
      .addCase(sendBackRecruitmentInstance.pending, (state: Draft<RecruitmentApprovalsState>) => {
        state.actionLoading = true;
        state.error = null;
      })
      .addCase(
        sendBackRecruitmentInstance.fulfilled,
        (
          state: Draft<RecruitmentApprovalsState>,
          action: PayloadAction<{ data: RecruitmentApprovalInstance; instanceId: string }>,
        ) => {
          removeFromPending(state, action.payload.instanceId);
          state.actionLoading = false;
          state.error = null;
        },
      )
      .addCase(
        sendBackRecruitmentInstance.rejected,
        (state: Draft<RecruitmentApprovalsState>, action: RejectedActionPayload) => {
          state.actionLoading = false;
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );

    builder
      .addCase(delegateRecruitmentApproval.pending, (state: Draft<RecruitmentApprovalsState>) => {
        state.actionLoading = true;
        state.error = null;
      })
      .addCase(
        delegateRecruitmentApproval.fulfilled,
        (
          state: Draft<RecruitmentApprovalsState>,
          action: PayloadAction<{ data: RecruitmentApprovalInstance; instanceId: string }>,
        ) => {
          removeFromPending(state, action.payload.instanceId);
          state.actionLoading = false;
          state.error = null;
        },
      )
      .addCase(
        delegateRecruitmentApproval.rejected,
        (state: Draft<RecruitmentApprovalsState>, action: RejectedActionPayload) => {
          state.actionLoading = false;
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );

    builder
      .addCase(cancelRecruitmentWorkflow.pending, (state: Draft<RecruitmentApprovalsState>) => {
        state.actionLoading = true;
        state.error = null;
      })
      .addCase(
        cancelRecruitmentWorkflow.fulfilled,
        (
          state: Draft<RecruitmentApprovalsState>,
          action: PayloadAction<{ data: RecruitmentApprovalInstance; instanceId: string }>,
        ) => {
          removeFromPending(state, action.payload.instanceId);
          state.actionLoading = false;
          state.error = null;
        },
      )
      .addCase(
        cancelRecruitmentWorkflow.rejected,
        (state: Draft<RecruitmentApprovalsState>, action: RejectedActionPayload) => {
          state.actionLoading = false;
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );
  },
});

export default RecruitmentApprovalsSlice;
export type { RecruitmentApprovalsState };
