import api from '@/lib/axios';
import { createSlice, createAsyncThunk, type PayloadAction } from '@reduxjs/toolkit';
import { toast } from 'sonner';

// Define types for nested entities
export interface PaymentPlan {
    id: number;
    name: string;
}

export interface ClientCompany {
    id: number;
    company_name: string;
}

export interface AuthorizedContact {
    id: number;
    first_name: string;
    last_name: string;
    email: string;
    client_company: ClientCompany;
}

// Define the main contract interface
export interface ClientContract {
    id: number;
    start_date: string;
    end_date: string;
    payment_plan_id: number;
    authorized_contact_id: number;
    description: string;
    payment_schedule: string;
    contract_document: string;
    terms_and_conditions: string;
    status?: string;
    created_at: string;
    updated_at: string;
    payment_plan: PaymentPlan;
    authorized_contact: AuthorizedContact;
}

// Define the state type
interface ClientContractsState {
    items: ClientContract[];
    count: number;
    currentContract: ClientContract | null;
    status: 'idle' | 'loading' | 'succeeded' | 'failed';
    error: string | null;
    filters: {
        search: string;
        companies: number[];
        paymentPlans: number[];
        status: string[];
        dateRange: {
            start: string;
            end: string;
        };
    };
}

// Initial state
const initialState: ClientContractsState = {
    items: [],
    count: 0,
    currentContract: null,
    status: 'idle',
    error: null,
    filters: {
        search: '',
        companies: [],
        paymentPlans: [],
        status: [],
        dateRange: {
            start: '',
            end: '',
        },
    },
};

// Define payload types - Now supporting FormData
export interface AddClientContractPayload {
    start_date: string;
    end_date: string;
    payment_plan_id: number;
    authorized_contact_id: number;
    description?: string;
    payment_schedule: string;
    contract_document?: File;
    terms_and_conditions?: string;
    status?: string;
}

export interface UpdateClientContractPayload {
    id: number;
    updates: FormData | Partial<AddClientContractPayload>;
}

// Async thunks for API calls
export const fetchClientContracts = createAsyncThunk(
    'clientContracts/fetchClientContracts',
    async (params: any, { rejectWithValue }) => {
        try {
            const response = await api.get('/contracts', { params });

            return response.data;
        } catch (error: any) {
            return rejectWithValue(error?.response?.data?.message || 'Failed to fetch client contracts');
        }
    },
);

export const addClientContract = createAsyncThunk(
    'clientContracts/addClientContract',
    async (payload: FormData | AddClientContractPayload, { rejectWithValue }) => {
        try {
            // Set proper headers for FormData
            const config = {
                headers: {
                    'Content-Type': 'multipart/form-data',
                },
            };

            const response = await api.post('/contracts', payload, config);
            return response;
        } catch (error: any) {
            return rejectWithValue(error?.response?.data?.message || 'Failed to add client contract');
        }
    },
);

export const updateClientContract = createAsyncThunk(
    'clientContracts/updateClientContract',
    async (payload: UpdateClientContractPayload, { rejectWithValue }) => {
        try {
            // Set proper headers for FormData
            const config =
                payload.updates instanceof FormData
                    ? {
                          headers: {
                              'Content-Type': 'multipart/form-data',
                          },
                      }
                    : undefined;

            const response = await api.patch(`/contracts/${payload.id}`, payload.updates, config);
            return response;
        } catch (error: any) {
            return rejectWithValue(error?.response?.data?.message || 'Failed to update client contract');
        }
    },
);

export const clientContractDetail = createAsyncThunk(
    'clientContracts/clientContractDetail',
    async (id: number, { rejectWithValue }) => {
        try {
            const response = await api.get(`/contracts/${id}`);
            return response.data.data;
        } catch (error: any) {
            return rejectWithValue(error?.response?.data?.message || 'Failed to fetch client contract detail');
        }
    },
);

export const deleteClientContract = createAsyncThunk(
    'clientContracts/deleteClientContract',
    async (id: number, { rejectWithValue }) => {
        try {
            const response = await api.delete(`/contracts/${id}`);
            return response;
        } catch (error: any) {
            return rejectWithValue(error?.response?.data?.message || 'Failed to delete client contract');
        }
    },
);

// Create the slice
const clientContractsSlice = createSlice({
    name: 'clientContracts',
    initialState,
    reducers: {
        // Clear current contract
        clearCurrentContract: (state) => {
            state.currentContract = null;
        },
        // Update filters
        updateFilters: (state, action: PayloadAction<Partial<ClientContractsState['filters']>>) => {
            state.filters = { ...state.filters, ...action.payload };
        },
        // Clear filters
        clearFilters: (state) => {
            state.filters = initialState.filters;
        },
        // Clear error
        clearError: (state) => {
            state.error = null;
        },
    },
    extraReducers: (builder) => {
        builder
            // Fetch contracts
            .addCase(fetchClientContracts.pending, (state) => {
                state.status = 'loading';
                state.error = null;
            })
            .addCase(fetchClientContracts.fulfilled, (state, action) => {
                state.status = 'succeeded';
                state.count = action.payload.data?.count || 0;
                state.items = action.payload?.data?.data || [];
                state.error = null;
            })
            .addCase(fetchClientContracts.rejected, (state, action) => {
                state.status = 'failed';
                state.error = (action.payload as string) || action.error.message || null;
            })

            // Add contract
            .addCase(addClientContract.pending, (state) => {
                state.error = null;
            })
            .addCase(addClientContract.fulfilled, (state, action) => {
                const code = action?.payload?.data?.code;
                if (code === 200 || code === 201) {
                    toast.success('Client contract added successfully');
                    // Optionally add the new contract to the items array if returned by API
                    const newContract = action?.payload?.data?.data;
                    if (newContract) {
                        state.items.unshift(newContract);
                        state.count += 1;
                    }
                } else if (code === 400 || code === 422) {
                    toast.error(action?.payload?.data?.message || 'Failed to add contract');
                } else if (code === 500) {
                    toast.error(action?.payload?.data?.message || 'Something went wrong');
                }
            })
            .addCase(addClientContract.rejected, (state, action) => {
                state.error = (action.payload as string) || action.error.message || null;
                toast.error(state.error || 'Failed to add contract');
            })

            // Update contract
            .addCase(updateClientContract.pending, (state) => {
                state.error = null;
            })
            .addCase(updateClientContract.fulfilled, (state, action: any) => {
                const code = action?.payload?.data?.code;
                if (code === 200) {
                    toast.success('Client contract updated successfully');
                    // Update the contract in the items array if needed
                    const updatedContract = action?.payload?.data?.data;
                    if (updatedContract) {
                        const index = state.items.findIndex((item) => item.id === updatedContract.id);
                        if (index !== -1) {
                            state.items[index] = updatedContract;
                        }
                        // Update current contract if it matches
                        if (state.currentContract?.id === updatedContract.id) {
                            state.currentContract = updatedContract;
                        }
                    }
                } else if (code === 400 || code === 422) {
                    toast.error(action?.payload?.data?.message || 'Failed to update contract');
                } else {
                    toast.error('Something went wrong');
                }
            })
            .addCase(updateClientContract.rejected, (state, action) => {
                state.error = (action.payload as string) || action.error.message || null;
                toast.error(state.error || 'Failed to update contract');
            })

            // Contract detail
            .addCase(clientContractDetail.pending, (state) => {
                state.error = null;
            })
            .addCase(clientContractDetail.fulfilled, (state, action) => {
                state.currentContract = action.payload;
                state.error = null;
            })
            .addCase(clientContractDetail.rejected, (state, action) => {
                state.error = (action.payload as string) || action.error.message || null;
                state.currentContract = null;
            })

            // Delete contract
            .addCase(deleteClientContract.pending, (state) => {
                state.error = null;
            })
            .addCase(deleteClientContract.fulfilled, (state, action: any) => {
                const code = action?.payload?.data?.code;
                if (code === 200) {
                    toast.success('Contract deleted successfully');
                    // Remove the contract from items array
                    const contractId = action?.meta?.arg; // The ID passed to the thunk
                    state.items = state.items.filter((item) => item.id !== contractId);
                    state.count = Math.max(0, state.count - 1);
                    // Clear current contract if it was deleted
                    if (state.currentContract?.id === contractId) {
                        state.currentContract = null;
                    }
                } else if (code === 400 || code === 422) {
                    toast.error(action?.payload?.data?.message || 'Failed to delete contract');
                } else {
                    toast.error('Something went wrong');
                }
            })
            .addCase(deleteClientContract.rejected, (state, action) => {
                state.error = (action.payload as string) || action.error.message || null;
                toast.error(state.error || 'Failed to delete contract');
            });
    },
});

// Export actions
export const { clearCurrentContract, updateFilters, clearFilters, clearError } = clientContractsSlice.actions;

export default clientContractsSlice.reducer;
