import {
  AdjustLeaveBalancePayload,
  ImportBalancesResult,
  LeaveBalance,
  LeaveBalanceFilters,
  LeaveBalanceListResponse,
  LeaveBalanceSingleResponse,
} from '@/interface/LeaveBalance';
import { RejectedActionPayload, ServerErrorResponse } from '@/interface/Shared';
import { apiGet, apiPost } 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 { LeaveBalancesActions } from './actionTypes';

interface LeaveBalancesState {
  balances: LeaveBalance[];
  myBalances: LeaveBalance[];
  employeeBalances: LeaveBalance[];
  loading: boolean;
  actionLoading: boolean;
  error: string | null;
  importResult: ImportBalancesResult | null;
}

const initialState: LeaveBalancesState = {
  balances: [],
  myBalances: [],
  employeeBalances: [],
  loading: false,
  actionLoading: false,
  error: null,
  importResult: null,
};

const buildQueryString = (filters?: LeaveBalanceFilters): string => {
  if (!filters) {
    return '';
  }

  const params = new URLSearchParams();

  if (filters.year) {
    params.set('year', String(filters.year));
  }

  if (filters.employee_id) {
    params.set('employee_id', filters.employee_id);
  }

  if (filters.leave_type_id) {
    params.set('leave_type_id', filters.leave_type_id);
  }

  if (filters.branch_id) {
    params.set('branch_id', filters.branch_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 extractListData = (payload: LeaveBalance[] | LeaveBalanceListResponse): LeaveBalance[] => {
  return Array.isArray(payload) ? payload : payload.data;
};

const extractSingleData = (payload: LeaveBalance[] | LeaveBalanceSingleResponse): LeaveBalance[] => {
  return Array.isArray(payload) ? payload : payload.data;
};

export const fetchLeaveBalances = createAsyncThunk(
  LeaveBalancesActions.FETCH_LEAVE_BALANCES_REQUEST,
  async (filters?: LeaveBalanceFilters) => {
    const response = (await apiGet(
      `/leave/balances${buildQueryString(filters)}`,
    )) as AxiosResponse<LeaveBalance[] | LeaveBalanceListResponse>;
    return extractListData(response.data);
  },
);

export const fetchMyBalances = createAsyncThunk(
  LeaveBalancesActions.FETCH_MY_BALANCES_REQUEST,
  async (year?: number) => {
    const query = year ? `?year=${year}` : '';
    const response = (await apiGet(`/leave/balances/me${query}`)) as AxiosResponse<
      LeaveBalance[] | LeaveBalanceSingleResponse
    >;
    return extractSingleData(response.data);
  },
);

export const fetchEmployeeBalances = createAsyncThunk(
  LeaveBalancesActions.FETCH_EMPLOYEE_BALANCES_REQUEST,
  async ({ employeeId, year }: { employeeId: string; year?: number }) => {
    const query = year ? `?year=${year}` : '';
    const response = (await apiGet(`/leave/balances/${employeeId}${query}`)) as AxiosResponse<
      LeaveBalance[] | LeaveBalanceSingleResponse
    >;
    return extractSingleData(response.data);
  },
);

export const adjustBalance = createAsyncThunk(
  LeaveBalancesActions.ADJUST_BALANCE_REQUEST,
  async (payload: AdjustLeaveBalancePayload, { rejectWithValue }) => {
    try {
      const response = (await apiPost(`/leave/balances/${payload.balance_id}/adjust`, {
        adjustment_days: payload.adjustment_days,
        reason: payload.reason,
      })) as AxiosResponse<{ data: LeaveBalance; message: string }>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const importBalances = createAsyncThunk(
  LeaveBalancesActions.IMPORT_BALANCES_REQUEST,
  async (file: File, { rejectWithValue }) => {
    try {
      const formData = new FormData();
      formData.append('file', file);
      const response = (await apiPost('/leave/balances/import', formData, {
        headers: {
          'Content-Type': 'multipart/form-data',
        },
      })) as AxiosResponse<ImportBalancesResult>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const LeaveBalancesSlice = createSlice({
  name: 'leaveBalances',
  initialState,
  reducers: {},
  extraReducers(builder) {
    builder
      .addCase(fetchLeaveBalances.pending, (state: Draft<LeaveBalancesState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(fetchLeaveBalances.fulfilled, (state: Draft<LeaveBalancesState>, action: PayloadAction<LeaveBalance[]>) => {
        state.balances = action.payload;
        state.loading = false;
        state.error = null;
      })
      .addCase(fetchLeaveBalances.rejected, (state: Draft<LeaveBalancesState>, action: RejectedActionPayload) => {
        state.loading = false;
        message.error(Helpers.handleServerError(action.payload), 8);
      });

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

    builder
      .addCase(fetchEmployeeBalances.pending, (state: Draft<LeaveBalancesState>) => {
        state.actionLoading = true;
        state.error = null;
      })
      .addCase(
        fetchEmployeeBalances.fulfilled,
        (state: Draft<LeaveBalancesState>, action: PayloadAction<LeaveBalance[]>) => {
          state.employeeBalances = action.payload;
          state.actionLoading = false;
          state.error = null;
        },
      )
      .addCase(fetchEmployeeBalances.rejected, (state: Draft<LeaveBalancesState>, action: RejectedActionPayload) => {
        state.actionLoading = false;
        message.error(Helpers.handleServerError(action.payload), 8);
      });

    builder
      .addCase(adjustBalance.pending, (state: Draft<LeaveBalancesState>) => {
        state.actionLoading = true;
        state.error = null;
      })
      .addCase(adjustBalance.fulfilled, (state: Draft<LeaveBalancesState>, action: PayloadAction<{ data: LeaveBalance; message: string }>) => {
        state.actionLoading = false;
        state.error = null;
        message.success(action.payload.message || 'Balance adjusted successfully');
      })
      .addCase(adjustBalance.rejected, (state: Draft<LeaveBalancesState>, action: RejectedActionPayload) => {
        state.actionLoading = false;
        state.error = Helpers.handleServerError(action.payload);
        message.error(state.error, 10);
      });

    builder
      .addCase(importBalances.pending, (state: Draft<LeaveBalancesState>) => {
        state.actionLoading = true;
        state.error = null;
      })
      .addCase(importBalances.fulfilled, (state: Draft<LeaveBalancesState>, action: PayloadAction<ImportBalancesResult>) => {
        state.actionLoading = false;
        state.importResult = action.payload;
        state.error = null;
        message.success(action.payload.message);
      })
      .addCase(importBalances.rejected, (state: Draft<LeaveBalancesState>, action: RejectedActionPayload) => {
        state.actionLoading = false;
        state.error = Helpers.handleServerError(action.payload);
        message.error(state.error, 10);
      });
  },
});

export default LeaveBalancesSlice;
export type { LeaveBalancesState };
