import {
  Bank,
  BankBranch,
  CreateBankBranchPayload,
  CreateBankPayload,
  DeleteBankBranchResponse,
  DeleteBankResponse,
} from '@/interface/Bank';
import { RejectedActionPayload, ServerErrorResponse } from '@/interface/Shared';
import { apiDelete, apiDownloadBlob, 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 { BankActions } from './actionTypes';

interface BankState {
  banks: Bank[];
  bankBranches: BankBranch[];
  loading: boolean;
  branchLoading: boolean;
  importing: boolean;
  error: string | null;
}

const initialState: BankState = {
  banks: [],
  bankBranches: [],
  loading: false,
  branchLoading: false,
  importing: false,
  error: null,
};

export const fetchBanks = createAsyncThunk(BankActions.FETCH_BANKS_REQUEST, async () => {
  const response = (await apiGet('/banks')) as AxiosResponse<Bank[]>;
  return response.data;
});

export const createBank = createAsyncThunk(
  BankActions.CREATE_BANK_REQUEST,
  async (payload: CreateBankPayload, { rejectWithValue }) => {
    try {
      const response = (await apiPost('/banks', payload)) as AxiosResponse<Bank>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const updateBank = createAsyncThunk(
  BankActions.UPDATE_BANK_REQUEST,
  async (payload: CreateBankPayload, { rejectWithValue }) => {
    try {
      const response = (await apiPut(
        `/banks/${payload.id}`,
        payload,
      )) as AxiosResponse<Bank>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const deleteBank = createAsyncThunk(
  BankActions.DELETE_BANK_REQUEST,
  async (payload: string) => {
    const response = (await apiDelete(
      `/banks/${payload}`,
    )) as AxiosResponse<DeleteBankResponse>;
    const responseData = response.data;
    responseData.id = payload;
    return responseData;
  },
);

export const fetchBankBranches = createAsyncThunk(
  BankActions.FETCH_BANK_BRANCHES_REQUEST,
  async (bankId: string) => {
    const response = (await apiGet(
      `/banks/${bankId}/branches`,
    )) as AxiosResponse<BankBranch[]>;
    return response.data;
  },
);

export const createBankBranch = createAsyncThunk(
  BankActions.CREATE_BANK_BRANCH_REQUEST,
  async (payload: CreateBankBranchPayload, { rejectWithValue }) => {
    try {
      const response = (await apiPost(
        `/banks/${payload.bank_id}/branches`,
        payload,
      )) as AxiosResponse<BankBranch>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const updateBankBranch = createAsyncThunk(
  BankActions.UPDATE_BANK_BRANCH_REQUEST,
  async (payload: CreateBankBranchPayload, { rejectWithValue }) => {
    try {
      const response = (await apiPut(
        `/banks/${payload.bank_id}/branches/${payload.id}`,
        payload,
      )) as AxiosResponse<BankBranch>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const deleteBankBranch = createAsyncThunk(
  BankActions.DELETE_BANK_BRANCH_REQUEST,
  async (payload: { bankId: string; branchId: string }) => {
    const response = (await apiDelete(
      `/banks/${payload.bankId}/branches/${payload.branchId}`,
    )) as AxiosResponse<DeleteBankBranchResponse>;
    const responseData = response.data;
    responseData.id = payload.branchId;
    return responseData;
  },
);

export const importBanks = createAsyncThunk(
  BankActions.IMPORT_BANKS_REQUEST,
  async (payload: FormData, { rejectWithValue }) => {
    try {
      const response = (await apiPost('/banks/import', payload)) as AxiosResponse<{
        message: string;
        count: number;
      }>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const downloadBankTemplate = createAsyncThunk(
  BankActions.DOWNLOAD_BANK_TEMPLATE,
  async () => {
    const response = await apiDownloadBlob('/banks/download-template');
    const url = window.URL.createObjectURL(new Blob([response.data]));
    const link = document.createElement('a');
    link.href = url;
    link.setAttribute('download', 'banks_import_template.xlsx');
    document.body.appendChild(link);
    link.click();
    link.remove();
    window.URL.revokeObjectURL(url);
  },
);

export const BankSlice = createSlice({
  name: 'banks',
  initialState,
  reducers: {
    clearBankBranches(state) {
      state.bankBranches = [];
    },
  },
  extraReducers(builder) {
    // Fetch banks
    builder
      .addCase(fetchBanks.pending, (state: Draft<BankState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(
        fetchBanks.fulfilled,
        (state: Draft<BankState>, action: PayloadAction<Bank[]>) => {
          state.banks = action.payload;
          state.error = null;
          state.loading = false;
        },
      )
      .addCase(fetchBanks.rejected, (state: Draft<BankState>) => {
        state.loading = false;
        message.error(
          'Failed to load Banks. Please try again or contact support if the issue persists',
        );
      });

    // Create bank
    builder
      .addCase(createBank.pending, (state: Draft<BankState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(
        createBank.fulfilled,
        (state: Draft<BankState>, action: PayloadAction<Bank>) => {
          state.banks.unshift(action.payload);
          state.error = null;
          state.loading = false;
        },
      )
      .addCase(
        createBank.rejected,
        (state: Draft<BankState>, action: RejectedActionPayload) => {
          state.loading = false;
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );

    // Update bank
    builder
      .addCase(updateBank.pending, (state: Draft<BankState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(
        updateBank.fulfilled,
        (state: Draft<BankState>, action: PayloadAction<Bank>) => {
          state.loading = false;
          state.error = null;
          const index = state.banks.findIndex((b) => b.id === action.payload.id);
          if (index !== -1) {
            state.banks[index] = action.payload;
          }
          message.success('Successfully updated Bank', 10);
        },
      )
      .addCase(
        updateBank.rejected,
        (state: Draft<BankState>, action: RejectedActionPayload) => {
          state.loading = false;
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );

    // Delete bank
    builder
      .addCase(deleteBank.pending, (state: Draft<BankState>) => {})
      .addCase(
        deleteBank.fulfilled,
        (state: Draft<BankState>, action: PayloadAction<DeleteBankResponse>) => {
          state.banks = state.banks.filter((bank) => bank.id !== action.payload.id);
          message.success(action.payload.message, 10);
        },
      )
      .addCase(deleteBank.rejected, (state: Draft<BankState>, action: RejectedActionPayload) => {
        message.error(Helpers.handleServerError(action.payload), 8);
      });

    // Fetch bank branches
    builder
      .addCase(fetchBankBranches.pending, (state: Draft<BankState>) => {
        state.branchLoading = true;
        state.error = null;
      })
      .addCase(
        fetchBankBranches.fulfilled,
        (state: Draft<BankState>, action: PayloadAction<BankBranch[]>) => {
          state.bankBranches = action.payload;
          state.error = null;
          state.branchLoading = false;
        },
      )
      .addCase(fetchBankBranches.rejected, (state: Draft<BankState>, action: RejectedActionPayload) => {
        state.branchLoading = false;
        message.error(Helpers.handleServerError(action.payload), 8);
      });

    // Create bank branch
    builder
      .addCase(createBankBranch.pending, (state: Draft<BankState>) => {
        state.branchLoading = true;
        state.error = null;
      })
      .addCase(
        createBankBranch.fulfilled,
        (state: Draft<BankState>, action: PayloadAction<BankBranch>) => {
          state.bankBranches.unshift(action.payload);
          state.error = null;
          state.branchLoading = false;
        },
      )
      .addCase(
        createBankBranch.rejected,
        (state: Draft<BankState>, action: RejectedActionPayload) => {
          state.branchLoading = false;
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );

    // Update bank branch
    builder
      .addCase(updateBankBranch.pending, (state: Draft<BankState>) => {
        state.branchLoading = true;
        state.error = null;
      })
      .addCase(
        updateBankBranch.fulfilled,
        (state: Draft<BankState>, action: PayloadAction<BankBranch>) => {
          state.branchLoading = false;
          state.error = null;
          const index = state.bankBranches.findIndex((b) => b.id === action.payload.id);
          if (index !== -1) {
            state.bankBranches[index] = action.payload;
          }
          message.success('Successfully updated Bank Branch', 10);
        },
      )
      .addCase(
        updateBankBranch.rejected,
        (state: Draft<BankState>, action: RejectedActionPayload) => {
          state.branchLoading = false;
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );

    // Delete bank branch
    builder
      .addCase(deleteBankBranch.pending, (state: Draft<BankState>) => {})
      .addCase(
        deleteBankBranch.fulfilled,
        (state: Draft<BankState>, action: PayloadAction<DeleteBankBranchResponse>) => {
          state.bankBranches = state.bankBranches.filter(
            (branch) => branch.id !== action.payload.id,
          );
          message.success(action.payload.message, 10);
        },
      )
      .addCase(deleteBankBranch.rejected, (state: Draft<BankState>, action: RejectedActionPayload) => {
        message.error(Helpers.handleServerError(action.payload), 8);
      });

    // Import banks
    builder
      .addCase(importBanks.pending, (state: Draft<BankState>) => {
        state.importing = true;
      })
      .addCase(
        importBanks.fulfilled,
        (state: Draft<BankState>, action: PayloadAction<{ message: string; count: number }>) => {
          state.importing = false;
          message.success(action.payload.message, 10);
        },
      )
      .addCase(
        importBanks.rejected,
        (state: Draft<BankState>, action: RejectedActionPayload) => {
          state.importing = false;
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );
  },
});

export const { clearBankBranches } = BankSlice.actions;
export default BankSlice;
export type { BankState };
