import {
  CreateGrievanceHearingPayload,
  CreateGrievancePayload,
  DeleteGrievanceDocumentPayload,
  Grievance,
  GrievanceDocument,
  GrievanceHearing,
  GrievanceStats,
  GrievanceTimeline,
  UpdateGrievanceHearingPayload,
  UpdateGrievancePayload,
  UpdateGrievanceStatusPayload,
  UploadGrievanceDocumentPayload,
} from '@/interface/Grievance';
import { RejectedActionPayload, ServerErrorResponse } from '@/interface/Shared';
import { apiDelete, apiGet, apiPost, apiPut } from '@/services/api/api';
import Helpers from '@/utilities/Helpers';
import { createAsyncThunk, createSlice, Draft, PayloadAction } from '@reduxjs/toolkit';
import { message } from 'antd';
import axios, { AxiosResponse } from 'axios';
import { GrievanceActions } from './actionTypes';

interface GrievanceState {
  grievances: Grievance[];
  grievance: Grievance | null;
  documents: GrievanceDocument[];
  timeline: GrievanceTimeline[];
  hearings: GrievanceHearing[];
  stats: GrievanceStats | null;
  loading: boolean;
  documentsLoading: boolean;
  hearingsLoading: boolean;
  timelineLoading: boolean;
  statsLoading: boolean;
  error: string | null;
}

const initialState: GrievanceState = {
  grievances: [],
  grievance: null,
  documents: [],
  timeline: [],
  hearings: [],
  stats: null,
  loading: false,
  documentsLoading: false,
  hearingsLoading: false,
  timelineLoading: false,
  statsLoading: false,
  error: null,
};

export const fetchGrievances = createAsyncThunk(
  GrievanceActions.FETCH_GRIEVANCES,
  async (queryString: string | undefined, { rejectWithValue }) => {
    try {
      const query = queryString ? `?${queryString}` : '';
      const response = (await apiGet(`/grievances${query}`)) as AxiosResponse<Grievance[]>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const fetchGrievance = createAsyncThunk(
  GrievanceActions.FETCH_GRIEVANCE,
  async (id: string, { rejectWithValue }) => {
    try {
      const response = (await apiGet(`/grievances/${id}`)) as AxiosResponse<Grievance>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const createGrievance = createAsyncThunk(
  GrievanceActions.CREATE_GRIEVANCE,
  async (payload: CreateGrievancePayload, { rejectWithValue }) => {
    try {
      const response = (await apiPost('/grievances', payload)) as AxiosResponse<Grievance>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const updateGrievance = createAsyncThunk(
  GrievanceActions.UPDATE_GRIEVANCE,
  async (payload: UpdateGrievancePayload, { rejectWithValue }) => {
    try {
      const { id, ...rest } = payload;
      const response = (await apiPut(`/grievances/${id}`, rest)) as AxiosResponse<Grievance>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const updateGrievanceStatus = createAsyncThunk(
  GrievanceActions.UPDATE_GRIEVANCE_STATUS,
  async (payload: UpdateGrievanceStatusPayload, { rejectWithValue }) => {
    try {
      const { id, ...rest } = payload;
      const response = (await apiPut(`/grievances/${id}/status`, rest)) as AxiosResponse<Grievance>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const deleteGrievance = createAsyncThunk(
  GrievanceActions.DELETE_GRIEVANCE,
  async (id: string, { rejectWithValue }) => {
    try {
      const response = (await apiDelete(`/grievances/${id}`)) as AxiosResponse<{ message: string }>;
      return { id, message: response.data.message };
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const fetchGrievanceDocuments = createAsyncThunk(
  GrievanceActions.FETCH_GRIEVANCE_DOCUMENTS,
  async (grievanceId: string, { rejectWithValue }) => {
    try {
      const response = (await apiGet(`/grievances/${grievanceId}/documents`)) as AxiosResponse<
        GrievanceDocument[]
      >;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const uploadGrievanceDocument = createAsyncThunk(
  GrievanceActions.UPLOAD_GRIEVANCE_DOCUMENT,
  async (payload: UploadGrievanceDocumentPayload, { rejectWithValue }) => {
    try {
      const formData = new FormData();
      formData.append('document_type', payload.document_type);
      formData.append('file', payload.file);

      const response = (await apiPost(`/grievances/${payload.grievance_id}/documents`, formData, {
        headers: {
          'Content-Type': 'multipart/form-data',
        },
      })) as AxiosResponse<GrievanceDocument>;

      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const deleteGrievanceDocument = createAsyncThunk(
  GrievanceActions.DELETE_GRIEVANCE_DOCUMENT,
  async (payload: DeleteGrievanceDocumentPayload, { rejectWithValue }) => {
    try {
      const response = (await apiDelete(
        `/grievances/${payload.grievance_id}/documents/${payload.document_id}`,
      )) as AxiosResponse<{ message: string }>;

      return {
        ...payload,
        message: response.data.message,
      };
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const fetchGrievanceTimeline = createAsyncThunk(
  GrievanceActions.FETCH_GRIEVANCE_TIMELINE,
  async (grievanceId: string, { rejectWithValue }) => {
    try {
      const response = (await apiGet(`/grievances/${grievanceId}/timeline`)) as AxiosResponse<
        GrievanceTimeline[]
      >;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const fetchGrievanceHearings = createAsyncThunk(
  GrievanceActions.FETCH_GRIEVANCE_HEARINGS,
  async (grievanceId: string, { rejectWithValue }) => {
    try {
      const response = (await apiGet(`/grievances/${grievanceId}/hearings`)) as AxiosResponse<
        GrievanceHearing[]
      >;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const createGrievanceHearing = createAsyncThunk(
  GrievanceActions.CREATE_GRIEVANCE_HEARING,
  async (payload: CreateGrievanceHearingPayload, { rejectWithValue }) => {
    try {
      const { grievance_id, ...rest } = payload;
      const response = (await apiPost(`/grievances/${grievance_id}/hearings`, rest)) as AxiosResponse<
        GrievanceHearing
      >;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const updateGrievanceHearing = createAsyncThunk(
  GrievanceActions.UPDATE_GRIEVANCE_HEARING,
  async (payload: UpdateGrievanceHearingPayload, { rejectWithValue }) => {
    try {
      const { grievance_id, hearing_id, ...rest } = payload;
      const response = (await apiPut(
        `/grievances/${grievance_id}/hearings/${hearing_id}`,
        rest,
      )) as AxiosResponse<GrievanceHearing>;

      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const fetchGrievanceStats = createAsyncThunk(
  GrievanceActions.FETCH_GRIEVANCE_STATS,
  async (_, { rejectWithValue }) => {
    try {
      const response = (await apiGet('/grievances/stats')) as AxiosResponse<GrievanceStats>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

const GrievanceSlice = createSlice({
  name: 'grievances',
  initialState,
  reducers: {
    clearGrievanceState: (state: Draft<GrievanceState>) => {
      state.grievance = null;
      state.documents = [];
      state.timeline = [];
      state.hearings = [];
    },
  },
  extraReducers(builder) {
    builder
      .addCase(fetchGrievances.pending, (state: Draft<GrievanceState>) => {
        state.loading = true;
      })
      .addCase(fetchGrievances.fulfilled, (state: Draft<GrievanceState>, action: PayloadAction<Grievance[]>) => {
        state.loading = false;
        state.grievances = action.payload;
      })
      .addCase(fetchGrievances.rejected, (state: Draft<GrievanceState>, action: RejectedActionPayload) => {
        state.loading = false;
        message.error(Helpers.handleServerError(action.payload), 10);
      });

    builder
      .addCase(fetchGrievance.pending, (state: Draft<GrievanceState>) => {
        state.loading = true;
      })
      .addCase(fetchGrievance.fulfilled, (state: Draft<GrievanceState>, action: PayloadAction<Grievance>) => {
        state.loading = false;
        state.grievance = action.payload;
      })
      .addCase(fetchGrievance.rejected, (state: Draft<GrievanceState>, action: RejectedActionPayload) => {
        state.loading = false;
        message.error(Helpers.handleServerError(action.payload), 10);
      });

    builder
      .addCase(createGrievance.pending, (state: Draft<GrievanceState>) => {
        state.loading = true;
      })
      .addCase(createGrievance.fulfilled, (state: Draft<GrievanceState>, action: PayloadAction<Grievance>) => {
        state.loading = false;
        state.grievances.unshift(action.payload);
        state.grievance = action.payload;
        message.success('Grievance filed successfully', 8);
      })
      .addCase(createGrievance.rejected, (state: Draft<GrievanceState>, action: RejectedActionPayload) => {
        state.loading = false;
        message.error(Helpers.handleServerError(action.payload), 10);
      });

    builder
      .addCase(updateGrievance.pending, (state: Draft<GrievanceState>) => {
        state.loading = true;
      })
      .addCase(updateGrievance.fulfilled, (state: Draft<GrievanceState>, action: PayloadAction<Grievance>) => {
        state.loading = false;
        state.grievance = action.payload;
        state.grievances = state.grievances.map((item) =>
          item.id === action.payload.id ? action.payload : item,
        );
        message.success('Grievance updated successfully', 8);
      })
      .addCase(updateGrievance.rejected, (state: Draft<GrievanceState>, action: RejectedActionPayload) => {
        state.loading = false;
        message.error(Helpers.handleServerError(action.payload), 10);
      });

    builder
      .addCase(updateGrievanceStatus.pending, (state: Draft<GrievanceState>) => {
        state.loading = true;
      })
      .addCase(
        updateGrievanceStatus.fulfilled,
        (state: Draft<GrievanceState>, action: PayloadAction<Grievance>) => {
          state.loading = false;
          state.grievance = action.payload;
          state.grievances = state.grievances.map((item) =>
            item.id === action.payload.id ? action.payload : item,
          );
          message.success('Status updated successfully', 8);
        },
      )
      .addCase(
        updateGrievanceStatus.rejected,
        (state: Draft<GrievanceState>, action: RejectedActionPayload) => {
          state.loading = false;
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );

    builder
      .addCase(deleteGrievance.fulfilled, (state: Draft<GrievanceState>, action) => {
        state.grievances = state.grievances.filter((item) => item.id !== action.payload.id);
        if (state.grievance?.id === action.payload.id) {
          state.grievance = null;
        }
        message.success(action.payload.message, 8);
      })
      .addCase(deleteGrievance.rejected, (state: Draft<GrievanceState>, action: RejectedActionPayload) => {
        message.error(Helpers.handleServerError(action.payload), 10);
      });

    builder
      .addCase(fetchGrievanceDocuments.pending, (state: Draft<GrievanceState>) => {
        state.documentsLoading = true;
      })
      .addCase(
        fetchGrievanceDocuments.fulfilled,
        (state: Draft<GrievanceState>, action: PayloadAction<GrievanceDocument[]>) => {
          state.documentsLoading = false;
          state.documents = action.payload;
        },
      )
      .addCase(
        fetchGrievanceDocuments.rejected,
        (state: Draft<GrievanceState>, action: RejectedActionPayload) => {
          state.documentsLoading = false;
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );

    builder
      .addCase(uploadGrievanceDocument.fulfilled, (state: Draft<GrievanceState>, action: PayloadAction<GrievanceDocument>) => {
        state.documents.unshift(action.payload);
        message.success('Document uploaded successfully', 8);
      })
      .addCase(
        uploadGrievanceDocument.rejected,
        (state: Draft<GrievanceState>, action: RejectedActionPayload) => {
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );

    builder
      .addCase(deleteGrievanceDocument.fulfilled, (state: Draft<GrievanceState>, action) => {
        state.documents = state.documents.filter((item) => item.id !== action.payload.document_id);
        message.success(action.payload.message, 8);
      })
      .addCase(
        deleteGrievanceDocument.rejected,
        (state: Draft<GrievanceState>, action: RejectedActionPayload) => {
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );

    builder
      .addCase(fetchGrievanceTimeline.pending, (state: Draft<GrievanceState>) => {
        state.timelineLoading = true;
      })
      .addCase(
        fetchGrievanceTimeline.fulfilled,
        (state: Draft<GrievanceState>, action: PayloadAction<GrievanceTimeline[]>) => {
          state.timelineLoading = false;
          state.timeline = action.payload;
        },
      )
      .addCase(fetchGrievanceTimeline.rejected, (state: Draft<GrievanceState>, action: RejectedActionPayload) => {
        state.timelineLoading = false;
        message.error(Helpers.handleServerError(action.payload), 10);
      });

    builder
      .addCase(fetchGrievanceHearings.pending, (state: Draft<GrievanceState>) => {
        state.hearingsLoading = true;
      })
      .addCase(
        fetchGrievanceHearings.fulfilled,
        (state: Draft<GrievanceState>, action: PayloadAction<GrievanceHearing[]>) => {
          state.hearingsLoading = false;
          state.hearings = action.payload;
        },
      )
      .addCase(fetchGrievanceHearings.rejected, (state: Draft<GrievanceState>, action: RejectedActionPayload) => {
        state.hearingsLoading = false;
        message.error(Helpers.handleServerError(action.payload), 10);
      });

    builder
      .addCase(createGrievanceHearing.fulfilled, (state: Draft<GrievanceState>, action: PayloadAction<GrievanceHearing>) => {
        state.hearings.unshift(action.payload);
        message.success('Hearing scheduled successfully', 8);
      })
      .addCase(createGrievanceHearing.rejected, (state: Draft<GrievanceState>, action: RejectedActionPayload) => {
        message.error(Helpers.handleServerError(action.payload), 10);
      });

    builder
      .addCase(updateGrievanceHearing.fulfilled, (state: Draft<GrievanceState>, action: PayloadAction<GrievanceHearing>) => {
        state.hearings = state.hearings.map((item) =>
          item.id === action.payload.id ? action.payload : item,
        );
        message.success('Hearing updated successfully', 8);
      })
      .addCase(updateGrievanceHearing.rejected, (state: Draft<GrievanceState>, action: RejectedActionPayload) => {
        message.error(Helpers.handleServerError(action.payload), 10);
      });

    builder
      .addCase(fetchGrievanceStats.pending, (state: Draft<GrievanceState>) => {
        state.statsLoading = true;
      })
      .addCase(fetchGrievanceStats.fulfilled, (state: Draft<GrievanceState>, action: PayloadAction<GrievanceStats>) => {
        state.statsLoading = false;
        state.stats = action.payload;
      })
      .addCase(fetchGrievanceStats.rejected, (state: Draft<GrievanceState>, action: RejectedActionPayload) => {
        state.statsLoading = false;
        message.error(Helpers.handleServerError(action.payload), 10);
      });
  },
});

export const { clearGrievanceState } = GrievanceSlice.actions;
export default GrievanceSlice;
export type { GrievanceState };
