import {
  CreateEmployeeRequestPayload,
  EmployeeRequest,
  EmployeeRequestActionResponse,
  EmployeeRequestFilters,
  EmployeeRequestListResponse,
  RequestType,
  RequestWorkflow,
} from '@/interface/EmployeeRequest';
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 { EmployeeRequestsActions } from './actionTypes';

interface EmployeeRequestsState {
  employeeRequests: EmployeeRequest[];
  myEmployeeRequests: EmployeeRequest[];
  selectedEmployeeRequest: EmployeeRequest | null;
  requestTypes: RequestType[];
  workflows: RequestWorkflow[];
  dashboard: {
    status_counts: Record<string, number>;
    type_counts: Array<{ type_name: string; count: number }>;
    my_pending_approvals: number;
    total_requests: number;
  } | null;
  loading: boolean;
  actionLoading: boolean;
  error: string | null;
}

const initialState: EmployeeRequestsState = {
  employeeRequests: [],
  myEmployeeRequests: [],
  selectedEmployeeRequest: null,
  requestTypes: [],
  workflows: [],
  dashboard: null,
  loading: false,
  actionLoading: false,
  error: null,
};

const buildQueryString = (filters?: EmployeeRequestFilters): string => {
  if (!filters) return '';
  const params = new URLSearchParams();
  if (filters.status) params.set('status', filters.status);
  if (filters.employee_id) params.set('employee_id', filters.employee_id);
  if (filters.request_type_id) params.set('request_type_id', filters.request_type_id);
  if (filters.search) params.set('search', filters.search);
  if (filters.per_page) params.set('per_page', String(filters.per_page));
  const query = params.toString();
  return query ? `?${query}` : '';
};

const extractCollectionData = (payload: EmployeeRequest[] | EmployeeRequestListResponse): EmployeeRequest[] => {
  return Array.isArray(payload) ? payload : payload.data;
};

const normalizeResponse = (data: EmployeeRequestActionResponse): EmployeeRequest => {
  if (data.data) return data.data;
  return data as unknown as EmployeeRequest;
};

const replaceInCollection = (collection: EmployeeRequest[], updated: EmployeeRequest): EmployeeRequest[] => {
  const index = collection.findIndex((item) => item.id === updated.id);
  if (index === -1) return collection;
  const next = [...collection];
  next[index] = updated;
  return next;
};

export const fetchEmployeeRequests = createAsyncThunk(
  EmployeeRequestsActions.FETCH_EMPLOYEE_REQUESTS,
  async (filters?: EmployeeRequestFilters) => {
    const response = (await apiGet(
      `/requests/applications${buildQueryString(filters)}`,
    )) as AxiosResponse<EmployeeRequest[] | EmployeeRequestListResponse>;
    return extractCollectionData(response.data);
  },
);

export const fetchMyEmployeeRequests = createAsyncThunk(
  EmployeeRequestsActions.FETCH_MY_EMPLOYEE_REQUESTS,
  async (filters?: EmployeeRequestFilters) => {
    const response = (await apiGet(
      `/requests/applications/my-requests${buildQueryString(filters)}`,
    )) as AxiosResponse<EmployeeRequest[] | EmployeeRequestListResponse>;
    return extractCollectionData(response.data);
  },
);

export const fetchEmployeeRequest = createAsyncThunk(
  EmployeeRequestsActions.FETCH_EMPLOYEE_REQUEST,
  async (id: string, { rejectWithValue }) => {
    try {
      const response = (await apiGet(`/requests/applications/${id}`)) as AxiosResponse<EmployeeRequestActionResponse>;
      return normalizeResponse(response.data);
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const createEmployeeRequest = createAsyncThunk(
  EmployeeRequestsActions.CREATE_EMPLOYEE_REQUEST,
  async (payload: CreateEmployeeRequestPayload, { rejectWithValue }) => {
    try {
      const response = (await apiPost('/requests/applications', payload)) as AxiosResponse<EmployeeRequestActionResponse>;
      return normalizeResponse(response.data);
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const deleteEmployeeRequest = createAsyncThunk(
  EmployeeRequestsActions.DELETE_EMPLOYEE_REQUEST,
  async (id: string) => {
    await apiDelete(`/requests/applications/${id}`);
    return id;
  },
);

export const submitEmployeeRequest = createAsyncThunk(
  EmployeeRequestsActions.SUBMIT_EMPLOYEE_REQUEST,
  async (id: string, { rejectWithValue }) => {
    try {
      const response = (await apiPost(`/requests/applications/${id}/submit`, {})) as AxiosResponse<EmployeeRequestActionResponse>;
      return normalizeResponse(response.data);
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const cancelEmployeeRequest = createAsyncThunk(
  EmployeeRequestsActions.CANCEL_EMPLOYEE_REQUEST,
  async (id: string, { rejectWithValue }) => {
    try {
      const response = (await apiPost(`/requests/applications/${id}/cancel`, {})) as AxiosResponse<EmployeeRequestActionResponse>;
      return normalizeResponse(response.data);
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const fetchRequestTypes = createAsyncThunk(
  EmployeeRequestsActions.FETCH_REQUEST_TYPES,
  async () => {
    const response = (await apiGet('/requests/request-types')) as AxiosResponse<RequestType[]>;
    return response.data;
  },
);

export const createRequestType = createAsyncThunk(
  EmployeeRequestsActions.CREATE_REQUEST_TYPE,
  async (payload: Partial<RequestType>, { rejectWithValue }) => {
    try {
      const response = (await apiPost('/requests/request-types', payload)) as AxiosResponse<RequestType>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const updateRequestType = createAsyncThunk(
  EmployeeRequestsActions.UPDATE_REQUEST_TYPE,
  async ({ id, ...payload }: Partial<RequestType> & { id: string }, { rejectWithValue }) => {
    try {
      const response = (await apiPut(`/requests/request-types/${id}`, payload)) as AxiosResponse<RequestType>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const deleteRequestType = createAsyncThunk(
  EmployeeRequestsActions.DELETE_REQUEST_TYPE,
  async (id: string) => {
    await apiDelete(`/requests/request-types/${id}`);
    return id;
  },
);

export const fetchRequestWorkflows = createAsyncThunk(
  EmployeeRequestsActions.FETCH_REQUEST_WORKFLOWS,
  async () => {
    const response = (await apiGet('/requests/workflows')) as AxiosResponse<RequestWorkflow[]>;
    return response.data;
  },
);

export const createRequestWorkflow = createAsyncThunk(
  EmployeeRequestsActions.CREATE_REQUEST_WORKFLOW,
  async (payload: Partial<RequestWorkflow>, { rejectWithValue }) => {
    try {
      const response = (await apiPost('/requests/workflows', payload)) as AxiosResponse<RequestWorkflow>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const updateRequestWorkflow = createAsyncThunk(
  EmployeeRequestsActions.UPDATE_REQUEST_WORKFLOW,
  async ({ id, ...payload }: Partial<RequestWorkflow> & { id: string }, { rejectWithValue }) => {
    try {
      const response = (await apiPut(`/requests/workflows/${id}`, payload)) as AxiosResponse<RequestWorkflow>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const deleteRequestWorkflow = createAsyncThunk(
  EmployeeRequestsActions.DELETE_REQUEST_WORKFLOW,
  async (id: string) => {
    await apiDelete(`/requests/workflows/${id}`);
    return id;
  },
);

export const assignRequestWorkflow = createAsyncThunk(
  EmployeeRequestsActions.ASSIGN_REQUEST_WORKFLOW,
  async (payload: { workflow_id: string; employee_id?: string; employee_category_id?: string; position_id?: string }, { rejectWithValue }) => {
    try {
      const response = (await apiPost('/requests/workflows-assignments', payload)) as AxiosResponse;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const fetchRequestDashboard = createAsyncThunk(
  EmployeeRequestsActions.FETCH_REQUEST_DASHBOARD,
  async () => {
    const response = (await apiGet('/requests/dashboard')) as AxiosResponse;
    return response.data;
  },
);

export const EmployeeRequestsSlice = createSlice({
  name: 'employeeRequests',
  initialState,
  reducers: {},
  extraReducers(builder) {
    builder
      .addCase(fetchEmployeeRequests.pending, (state: Draft<EmployeeRequestsState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(fetchEmployeeRequests.fulfilled, (state: Draft<EmployeeRequestsState>, action: PayloadAction<EmployeeRequest[]>) => {
        state.employeeRequests = action.payload;
        state.loading = false;
        state.error = null;
      })
      .addCase(fetchEmployeeRequests.rejected, (state: Draft<EmployeeRequestsState>, action: RejectedActionPayload) => {
        state.loading = false;
        message.error(Helpers.handleServerError(action.payload), 8);
      });

    builder
      .addCase(fetchMyEmployeeRequests.pending, (state: Draft<EmployeeRequestsState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(fetchMyEmployeeRequests.fulfilled, (state: Draft<EmployeeRequestsState>, action: PayloadAction<EmployeeRequest[]>) => {
        state.myEmployeeRequests = action.payload;
        state.loading = false;
        state.error = null;
      })
      .addCase(fetchMyEmployeeRequests.rejected, (state: Draft<EmployeeRequestsState>, action: RejectedActionPayload) => {
        state.loading = false;
        message.error(Helpers.handleServerError(action.payload), 8);
      });

    builder
      .addCase(fetchEmployeeRequest.pending, (state: Draft<EmployeeRequestsState>) => {
        state.actionLoading = true;
        state.error = null;
      })
      .addCase(fetchEmployeeRequest.fulfilled, (state: Draft<EmployeeRequestsState>, action: PayloadAction<EmployeeRequest>) => {
        state.selectedEmployeeRequest = action.payload;
        state.actionLoading = false;
        state.error = null;
      })
      .addCase(fetchEmployeeRequest.rejected, (state: Draft<EmployeeRequestsState>, action: RejectedActionPayload) => {
        state.actionLoading = false;
        state.error = Helpers.handleServerError(action.payload);
        message.error(state.error, 10);
      });

    builder
      .addCase(createEmployeeRequest.pending, (state: Draft<EmployeeRequestsState>) => {
        state.actionLoading = true;
        state.error = null;
      })
      .addCase(createEmployeeRequest.fulfilled, (state: Draft<EmployeeRequestsState>, action: PayloadAction<EmployeeRequest>) => {
        state.actionLoading = false;
        state.error = null;
        state.employeeRequests.unshift(action.payload);
        state.myEmployeeRequests.unshift(action.payload);
        state.selectedEmployeeRequest = action.payload;
        message.success('Request saved successfully.');
      })
      .addCase(createEmployeeRequest.rejected, (state: Draft<EmployeeRequestsState>, action: RejectedActionPayload) => {
        state.actionLoading = false;
        state.error = Helpers.handleServerError(action.payload);
        message.error(state.error, 10);
      });

    builder
      .addCase(deleteEmployeeRequest.pending, (state: Draft<EmployeeRequestsState>) => {
        state.actionLoading = true;
      })
      .addCase(deleteEmployeeRequest.fulfilled, (state: Draft<EmployeeRequestsState>, action: PayloadAction<string>) => {
        state.actionLoading = false;
        state.employeeRequests = state.employeeRequests.filter((item) => item.id !== action.payload);
        state.myEmployeeRequests = state.myEmployeeRequests.filter((item) => item.id !== action.payload);
        if (state.selectedEmployeeRequest?.id === action.payload) {
          state.selectedEmployeeRequest = null;
        }
        message.success('Request deleted successfully.');
      })
      .addCase(deleteEmployeeRequest.rejected, (state: Draft<EmployeeRequestsState>, action: RejectedActionPayload) => {
        state.actionLoading = false;
        message.error(Helpers.handleServerError(action.payload), 8);
      });

    builder
      .addCase(submitEmployeeRequest.pending, (state: Draft<EmployeeRequestsState>) => {
        state.actionLoading = true;
        state.error = null;
      })
      .addCase(submitEmployeeRequest.fulfilled, (state: Draft<EmployeeRequestsState>, action: PayloadAction<EmployeeRequest>) => {
        state.actionLoading = false;
        state.error = null;
        const merged = state.selectedEmployeeRequest
          ? { ...state.selectedEmployeeRequest, ...action.payload }
          : action.payload;
        state.employeeRequests = replaceInCollection(state.employeeRequests, merged);
        state.myEmployeeRequests = replaceInCollection(state.myEmployeeRequests, merged);
        state.selectedEmployeeRequest = merged;
        message.success('Request submitted for approval.');
      })
      .addCase(submitEmployeeRequest.rejected, (state: Draft<EmployeeRequestsState>, action: RejectedActionPayload) => {
        state.actionLoading = false;
        state.error = Helpers.handleServerError(action.payload);
        message.error(state.error, 10);
      });

    builder
      .addCase(cancelEmployeeRequest.pending, (state: Draft<EmployeeRequestsState>) => {
        state.actionLoading = true;
        state.error = null;
      })
      .addCase(cancelEmployeeRequest.fulfilled, (state: Draft<EmployeeRequestsState>, action: PayloadAction<EmployeeRequest>) => {
        state.actionLoading = false;
        state.error = null;
        const merged = state.selectedEmployeeRequest
          ? { ...state.selectedEmployeeRequest, ...action.payload }
          : action.payload;
        state.employeeRequests = replaceInCollection(state.employeeRequests, merged);
        state.myEmployeeRequests = replaceInCollection(state.myEmployeeRequests, merged);
        state.selectedEmployeeRequest = merged;
        message.success('Request cancelled.');
      })
      .addCase(cancelEmployeeRequest.rejected, (state: Draft<EmployeeRequestsState>, action: RejectedActionPayload) => {
        state.actionLoading = false;
        state.error = Helpers.handleServerError(action.payload);
        message.error(state.error, 10);
      });

    builder
      .addCase(fetchRequestTypes.pending, (state: Draft<EmployeeRequestsState>) => {
        state.loading = true;
      })
      .addCase(fetchRequestTypes.fulfilled, (state: Draft<EmployeeRequestsState>, action: PayloadAction<RequestType[]>) => {
        state.requestTypes = action.payload;
        state.loading = false;
      })
      .addCase(fetchRequestTypes.rejected, (state: Draft<EmployeeRequestsState>) => {
        state.loading = false;
      });

    builder
      .addCase(createRequestType.pending, (state: Draft<EmployeeRequestsState>) => {
        state.actionLoading = true;
        state.error = null;
      })
      .addCase(createRequestType.fulfilled, (state: Draft<EmployeeRequestsState>, action: PayloadAction<RequestType>) => {
        state.actionLoading = false;
        state.requestTypes.push(action.payload);
        message.success('Request type created.');
      })
      .addCase(createRequestType.rejected, (state: Draft<EmployeeRequestsState>, action: RejectedActionPayload) => {
        state.actionLoading = false;
        state.error = Helpers.handleServerError(action.payload);
        message.error(state.error, 10);
      });

    builder
      .addCase(updateRequestType.pending, (state: Draft<EmployeeRequestsState>) => {
        state.actionLoading = true;
        state.error = null;
      })
      .addCase(updateRequestType.fulfilled, (state: Draft<EmployeeRequestsState>, action: PayloadAction<RequestType>) => {
        state.actionLoading = false;
        const idx = state.requestTypes.findIndex((t) => t.id === action.payload.id);
        if (idx !== -1) state.requestTypes[idx] = action.payload;
        message.success('Request type updated.');
      })
      .addCase(updateRequestType.rejected, (state: Draft<EmployeeRequestsState>, action: RejectedActionPayload) => {
        state.actionLoading = false;
        state.error = Helpers.handleServerError(action.payload);
        message.error(state.error, 10);
      });

    builder
      .addCase(deleteRequestType.pending, (state: Draft<EmployeeRequestsState>) => {
        state.actionLoading = true;
      })
      .addCase(deleteRequestType.fulfilled, (state: Draft<EmployeeRequestsState>, action: PayloadAction<string>) => {
        state.actionLoading = false;
        state.requestTypes = state.requestTypes.filter((t) => t.id !== action.payload);
        message.success('Request type deleted.');
      })
      .addCase(deleteRequestType.rejected, (state: Draft<EmployeeRequestsState>, action: RejectedActionPayload) => {
        state.actionLoading = false;
        message.error(Helpers.handleServerError(action.payload), 8);
      });

    builder
      .addCase(fetchRequestWorkflows.fulfilled, (state: Draft<EmployeeRequestsState>, action: PayloadAction<RequestWorkflow[]>) => {
        state.workflows = action.payload;
      });

    builder
      .addCase(createRequestWorkflow.pending, (state: Draft<EmployeeRequestsState>) => {
        state.actionLoading = true;
        state.error = null;
      })
      .addCase(createRequestWorkflow.fulfilled, (state: Draft<EmployeeRequestsState>, action: PayloadAction<RequestWorkflow>) => {
        state.actionLoading = false;
        state.workflows.push(action.payload);
        message.success('Workflow created.');
      })
      .addCase(createRequestWorkflow.rejected, (state: Draft<EmployeeRequestsState>, action: RejectedActionPayload) => {
        state.actionLoading = false;
        state.error = Helpers.handleServerError(action.payload);
        message.error(state.error, 10);
      });

    builder
      .addCase(updateRequestWorkflow.pending, (state: Draft<EmployeeRequestsState>) => {
        state.actionLoading = true;
        state.error = null;
      })
      .addCase(updateRequestWorkflow.fulfilled, (state: Draft<EmployeeRequestsState>, action: PayloadAction<RequestWorkflow>) => {
        state.actionLoading = false;
        const idx = state.workflows.findIndex((w) => w.id === action.payload.id);
        if (idx !== -1) state.workflows[idx] = action.payload;
        message.success('Workflow updated.');
      })
      .addCase(updateRequestWorkflow.rejected, (state: Draft<EmployeeRequestsState>, action: RejectedActionPayload) => {
        state.actionLoading = false;
        state.error = Helpers.handleServerError(action.payload);
        message.error(state.error, 10);
      });

    builder
      .addCase(deleteRequestWorkflow.pending, (state: Draft<EmployeeRequestsState>) => {
        state.actionLoading = true;
      })
      .addCase(deleteRequestWorkflow.fulfilled, (state: Draft<EmployeeRequestsState>, action: PayloadAction<string>) => {
        state.actionLoading = false;
        state.workflows = state.workflows.filter((w) => w.id !== action.payload);
        message.success('Workflow deleted.');
      })
      .addCase(deleteRequestWorkflow.rejected, (state: Draft<EmployeeRequestsState>, action: RejectedActionPayload) => {
        state.actionLoading = false;
        message.error(Helpers.handleServerError(action.payload), 8);
      });

    builder
      .addCase(assignRequestWorkflow.pending, (state: Draft<EmployeeRequestsState>) => {
        state.actionLoading = true;
        state.error = null;
      })
      .addCase(assignRequestWorkflow.fulfilled, (state: Draft<EmployeeRequestsState>) => {
        state.actionLoading = false;
        message.success('Workflow assigned.');
      })
      .addCase(assignRequestWorkflow.rejected, (state: Draft<EmployeeRequestsState>, action: RejectedActionPayload) => {
        state.actionLoading = false;
        state.error = Helpers.handleServerError(action.payload);
        message.error(state.error, 10);
      });

    builder
      .addCase(fetchRequestDashboard.fulfilled, (state: Draft<EmployeeRequestsState>, action) => {
        state.dashboard = action.payload;
      });
  },
});

export default EmployeeRequestsSlice;
export type { EmployeeRequestsState };
