import api from '@/lib/axios';
import { handleToastError } from '@/lib/utils';
import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit';
import { toast } from 'sonner';
import messages from '../../../messages/en.json';

export interface Payment {
    id: number;
    invoice_id: number;
    amount: string;
    payment_method?: string;
    reference_number?: string;
    notes?: string;
    payment_date?: string;
    status?: string;
    created_at?: string;
    updated_at?: string;
    invoice?: {
        id: number;
        invoice_type: string;
        start_date: string;
        end_date: string;
        due_date: string;
        total_amount: string;
        customer: {
            id: number;
            customer_name: string;
            is_medical_tourist: boolean;
        };
    };
    client_company?: {
        id: number;
        company_name: string;
    } | null;
}

interface PaymentsState {
    items: Payment[];
    status: 'idle' | 'loading' | 'succeeded' | 'failed';
    error: string | null;
    filters: {
        search: string;
        skip: number;
        limit: number;
        sortBy?: string;
        sortOrder?: 'ASC' | 'DESC';
        payment_method?: string;
    };
    totalCount: number;
    selectedPayment: Payment | null;
}

interface GetPaymentsParams {
    limit?: number;
    skip?: number;
    search?: string;
    sortBy?: string;
    payment_method?: string;
    sortOrder?: 'ASC' | 'DESC';
}

const initialState: PaymentsState = {
    items: [],
    status: 'idle',
    error: null,
    filters: {
        search: '',
        limit: 10,
        skip: 0,
        sortBy: '',
        sortOrder: 'DESC',
        payment_method: '',
    },
    totalCount: 0,
    selectedPayment: null,
};

export const fetchPayments = createAsyncThunk(
    'payments/fetchPayments',
    async (params: {
        skip?: number;
        limit?: number;
        search?: string;
        sortBy?: string;
        sortOrder?: 'ASC' | 'DESC';
        payment_method?: string;
    }) => {
        try {
            const response = await api.get(`/payments`, { params });

            return {
                data: response.data.data?.data || [],
                count: response.data.data?.count || 0,
            };
        } catch (error: any) {
            throw error.response?.data || error.message;
        }
    },
);

export const addPayment = createAsyncThunk('payments/addPayment', async (payload: Omit<Payment, 'id'>) => {
    try {
        const response = await api.post(`/payments`, payload);
        return response;
    } catch (error: any) {
        return error.response;
    }
});

export const updatePayment = createAsyncThunk('payments/updatePayment', async ({ id, ...payload }: Payment & { id: number }) => {
    try {
        const response = await api.patch(`/payments/${id}`, payload);
        return response;
    } catch (error: any) {
        return error.response;
    }
});

export const deletePayment = createAsyncThunk('payments/deletePayment', async (id: number) => {
    try {
        const response = await api.delete(`/payments/${id}`);
        handleToastError(response);
        return response;
    } catch (error: any) {
        handleToastError(error);
        return error.response;
    }
});

export const fetchPaymentById = createAsyncThunk('payments/fetchPaymentById', async (id: number) => {
    try {
        const response = await api.get(`/payments/${id}`);
        return response.data;
    } catch (error: any) {
        throw error.response?.data || error.message;
    }
});

export const exportPayments = createAsyncThunk<any, GetPaymentsParams>(
    'payments/exportPayments',
    async (params, { rejectWithValue }) => {
        try {
            const response = await api.get('/payments/excel/export', {
                params,
                responseType: 'blob',
            });
            return response.data;
        } catch (error: any) {
            return rejectWithValue(error?.response?.data?.message || messages.toasts.error.failed_to_export_payments);
        }
    },
);

const paymentsSlice = createSlice({
    name: 'payments',
    initialState,
    reducers: {
        updateFilters: (state, action: PayloadAction<Partial<PaymentsState['filters']>>) => {
            state.filters = { ...state.filters, ...action.payload };
        },
        resetFilters: (state) => {
            state.filters = initialState.filters;
        },
        clearSelectedPayment: (state) => {
            state.selectedPayment = null;
        },
    },
    extraReducers: (builder) => {
        builder
            // Fetch payments
            .addCase(fetchPayments.pending, (state) => {
                state.status = 'loading';
            })
            .addCase(fetchPayments.fulfilled, (state, action) => {
                state.status = 'succeeded';
                state.items = action.payload.data as Payment[];
                state.totalCount = action.payload.count;
            })
            .addCase(fetchPayments.rejected, (state, action) => {
                state.status = 'failed';
                state.error = action.payload as string;
            })

            // Add payment
            .addCase(addPayment.fulfilled, (state, action) => {
                const code = action.payload?.data?.code;
                if (code === 200 || code === 201) {
                    state.items.unshift(action.payload.data.data);
                    toast.success(messages.toasts.success.payment_added);
                } else {
                    toast.error(action.payload?.data?.message || messages.toasts.error.generic);
                }
            })
            .addCase(addPayment.rejected, (state, action) => {
                toast.error(messages.toasts.error.failed_to_add_payment);
            })

            // Update payment
            .addCase(updatePayment.fulfilled, (state, action) => {
                const code = action.payload?.data?.code;
                if (code === 200 || code === 201) {
                    const index = state.items.findIndex((item) => item.id === action.payload.data.data.id);
                    if (index !== -1) {
                        state.items[index] = action.payload.data.data;
                    }
                    toast.success(messages.toasts.success.payment_updated);
                } else {
                    toast.error(action.payload?.data?.message || messages.toasts.error.generic);
                }
            })
            .addCase(updatePayment.rejected, (state, action) => {
                toast.error(messages.toasts.error.failed_to_update_payment);
            })

            // Delete payment
            .addCase(deletePayment.fulfilled, (state, action) => {
                const code = action.payload?.data?.code;
                if (code === 200) {
                    toast.success(messages.toasts.success.payment_deleted);
                } else {
                    toast.error(action.payload?.data?.message || messages.toasts.error.generic);
                }
            })
            .addCase(deletePayment.rejected, (state, action) => {
                toast.error(messages.toasts.error.failed_to_delete_payment);
            })

            // Fetch by ID
            .addCase(fetchPaymentById.pending, (state) => {
                state.status = 'loading';
                state.selectedPayment = null;
            })
            .addCase(fetchPaymentById.fulfilled, (state, action) => {
                state.status = 'succeeded';
                state.selectedPayment = action.payload.data;
            })
            .addCase(fetchPaymentById.rejected, (state, action) => {
                state.status = 'failed';
                state.error = action.error.message || messages.toasts.error.failed_to_fetch_payment_details;
                toast.error(messages.toasts.error.failed_to_fetch_payment_details);
            })
            .addCase(exportPayments.pending, (state) => {
                state.error = null;
            })
            .addCase(exportPayments.fulfilled, (state, action: PayloadAction<any>) => {
                state.status = 'succeeded';
                // Export doesn't update the items, just handles the download
            })
            .addCase(exportPayments.rejected, (state, action) => {
                state.status = 'failed';
                state.error = (action.payload as string) || messages.toasts.error.failed_to_export_payments;
            });
    },
});

export const { updateFilters, resetFilters, clearSelectedPayment } = paymentsSlice.actions;
export default paymentsSlice.reducer;
