import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit';

import api from '@/lib/axios';
import { handleToastError } from '@/lib/utils';
import { toast } from 'sonner';
import messages from '../../../messages/en.json';

// City interface
export interface City {
    id: number;
    name: string;
    state_id: number;
    country_id: number;
}

// CitiesState interface
interface CitiesState {
    items: City[];
    status: 'idle' | 'loading' | 'succeeded' | 'failed';
    error: string | null;
    selectedCity: City | null;
    token: string | null;
    totalCount: number;
    filters: {
        search?: { [key: string]: string };
        limit: number;
        skip: number;
        sortBy?: string;
        sortOrder?: 'ASC' | 'DESC';
        stateId?: number;
        countryId?: number;
    };
    cityDetails: {
        id: number;
        name: string;
        state: {
            id: number;
            name: string;
        };
        country: {
            id: number;
            name: string;
        };
    } | null;
}

// Initial state
const initialState: CitiesState = {
    items: [],
    status: 'idle',
    cityDetails: null,
    error: null,
    selectedCity: null,
    token: null,
    totalCount: 0,
    filters: {
        search: {},
        limit: 10,
        skip: 0,
        sortBy: '',
        sortOrder: 'ASC',
        countryId: undefined,
        stateId: undefined,
    },
};

// Async Thunks
export const fetchCities = createAsyncThunk(
    'cities/fetchCities',
    async (payload: { countryIds?: string; stateIds?: string } | undefined, { getState, rejectWithValue }) => {
        try {
            const state = getState() as { cities: CitiesState };

            const { search, limit, skip, sortBy, sortOrder, stateId, countryId } = state?.cities?.filters;

            // Build query parameters object
            const params = {
                limit,
                skip,
                ...(sortBy && { sortBy }),
                ...(sortOrder && { sortOrder }),
                ...(stateId && { stateId }),
                ...(payload?.stateIds && { state_id: payload.stateIds }),
                ...(stateId && !payload?.stateIds && { state_id: stateId }),
                ...(payload?.countryIds && { country_id: payload.countryIds }),
                ...(countryId && !payload?.countryIds && { country_id: countryId }),
                ...(search && typeof search === 'object' && search.name ? { search: search.name } : {}),
                ...(search && typeof search === 'string' ? { search } : {}),
            };

            // Convert params object to URL query string
            const queryParams = new URLSearchParams();
            Object.entries(params).forEach(([key, value]) => {
                if (value !== undefined) {
                    queryParams.append(key, value.toString());
                }
            });

            const response = await api.get(`/city?${queryParams.toString()}`, {});
            return response.data;
        } catch (error) {
            return rejectWithValue(error instanceof Error ? error.message : 'Failed to fetch cities');
        }
    },
);

export const createCity = createAsyncThunk(
    'cities/createCity',
    async (cityData: Partial<City>, { getState, rejectWithValue }) => {
        try {
            const response = await api.post(`/city`, cityData);
            return response;
        } catch (error: any) {
            handleToastError(error?.response);

            return rejectWithValue(error?.response?.data || error.message);
        }
    },
);

export const getCityById = createAsyncThunk('cities/getCityById', async (id: number, { getState, rejectWithValue }) => {
    try {
        const response = await api.get(`/city/${id}`);
        return response.data;
    } catch (error) {
        return rejectWithValue(error instanceof Error ? error.message : 'Failed to fetch city details');
    }
});

export const updateCity = createAsyncThunk(
    'cities/updateCity',
    async ({ id, ...cityData }: { id: number } & Partial<City>, { getState, rejectWithValue }) => {
        try {
            const response = await api.patch(`/city/${id}`, cityData);
            return response.data;
        } catch (error) {
            return rejectWithValue(error instanceof Error ? error.message : 'Failed to update city');
        }
    },
);

export const deleteCity = createAsyncThunk('cities/deleteCity', async (id: number, { rejectWithValue }) => {
    try {
        const response = await api.delete(`/city/${id}`);

        if (response?.data?.success === false) {
            toast.error(response.data.message || messages.toasts.error.failed_to_delete_city);
            return rejectWithValue(response.data.message || 'Deletion failed');
        }

        toast.success(messages.toasts.success.city_deleted);
        return id;
    } catch (error) {
        return rejectWithValue(error instanceof Error ? error.message : 'Failed to delete state');
    }
});

export const fetchCitiesByState = createAsyncThunk(
    'cities/fetchCitiesByState',
    async (stateId: number, { getState, rejectWithValue }) => {
        try {
            const response = await api.get(`/city/list/state/${stateId}`);
            return response.data;
        } catch (error) {
            return rejectWithValue(error instanceof Error ? error.message : 'Failed to fetch cities by state');
        }
    },
);

export const fetchCitiesByCountry = createAsyncThunk(
    'cities/fetchCitiesByCountry',
    async (countryId: number, { getState, rejectWithValue }) => {
        try {
            const response = await api.get(`/city/list/country/${countryId}`);
            return response.data;
        } catch (error) {
            return rejectWithValue(error instanceof Error ? error.message : 'Failed to fetch cities by country');
        }
    },
);

export const getCityDetailsForDropdown = createAsyncThunk(
    'cities/getCityDetailsForDropdown',
    async (cityId: number, { getState, rejectWithValue }) => {
        try {
            const response = await api.get(`/city/details/${cityId}`);
            return response.data.data;
        } catch (error) {
            return rejectWithValue(error instanceof Error ? error.message : 'Failed to fetch city details');
        }
    },
);

export const getCityStateCountry = createAsyncThunk('location/getCityStateCountry', async (payload: any, { rejectWithValue }) => {
    try {
        const response = await api.post(`/city/location`, payload);

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

// Create the slice
const citiesSlice = createSlice({
    name: 'cities',
    initialState,
    reducers: {
        setSelectedCity: (state, action: PayloadAction<City | null>) => {
            state.selectedCity = action.payload;
        },
        updateFilters: (state, action: PayloadAction<Partial<CitiesState['filters']>>) => {
            state.filters = { ...state.filters, ...action.payload };
        },
        resetFilters: (state) => {
            state.filters = initialState.filters;
        },
        setAuthToken: (state, action: PayloadAction<string | null>) => {
            state.token = action.payload;

            // Only interact with localStorage on the client side
            if (typeof window !== 'undefined') {
                if (action.payload) {
                    localStorage.setItem('token', action.payload);
                } else {
                    localStorage.removeItem('token');
                }
            }
        },
    },
    extraReducers: (builder) => {
        builder
            .addCase(fetchCities.pending, (state) => {
                state.status = 'loading';
            })
            .addCase(fetchCities.fulfilled, (state, action) => {
                state.status = 'succeeded';
                state.items = action?.payload;
            })
            .addCase(fetchCities.rejected, (state, action) => {
                state.status = 'failed';
                state.error = action.payload as string;
            })
            .addCase(createCity.pending, (state) => {
                state.status = 'loading';
                state.error = null;
            })
            .addCase(createCity.fulfilled, (state) => {
                state.status = 'succeeded';
            })
            .addCase(createCity.rejected, (state, action) => {
                state.status = 'failed';
                state.error = action.payload as string;
            })
            .addCase(updateCity.pending, (state) => {
                state.status = 'loading';
            })
            .addCase(updateCity.fulfilled, (state) => {
                state.status = 'succeeded';
            })
            .addCase(updateCity.rejected, (state, action) => {
                state.status = 'failed';
                state.error = action.payload as string;
            })
            .addCase(getCityById.pending, (state) => {
                state.status = 'loading';
            })
            .addCase(getCityById.fulfilled, (state, action) => {
                state.status = 'succeeded';
                state.selectedCity = action.payload;
            })
            .addCase(getCityById.rejected, (state, action) => {
                state.status = 'failed';
                state.error = action.payload as string;
                state.selectedCity = null;
            })
            .addCase(deleteCity.pending, (state) => {
                state.status = 'loading';
            })
            .addCase(deleteCity.fulfilled, (state, action) => {
                state.status = 'succeeded';

                // Safely handle different data structures
                if (state.items?.data?.data) {
                    state.items.data.data = state.items.data.data.filter((city) => city.id !== action.payload);

                    // Optionally, update the total count
                    if (state.items.data.count > 0) {
                        state.items.data.count -= 1;
                    }
                } else if (Array.isArray(state.items)) {
                    // Fallback if items is a direct array
                    state.items = state.items.filter((city) => city.id !== action.payload);
                }
            })
            .addCase(deleteCity.rejected, (state, action) => {
                state.status = 'failed';
                state.error = action.payload as string;
            })
            .addCase(fetchCitiesByState.pending, (state) => {
                state.status = 'loading';
            })
            .addCase(fetchCitiesByState.fulfilled, (state, action) => {
                state.status = 'succeeded';
                state.items = action.payload;
            })
            .addCase(fetchCitiesByState.rejected, (state, action) => {
                state.status = 'failed';
                state.error = action.payload as string;
            })
            .addCase(fetchCitiesByCountry.pending, (state) => {
                state.status = 'loading';
            })
            .addCase(fetchCitiesByCountry.fulfilled, (state, action) => {
                state.status = 'succeeded';
                state.items = action.payload;
            })
            .addCase(fetchCitiesByCountry.rejected, (state, action) => {
                state.status = 'failed';
                state.error = action.payload as string;
            })
            .addCase(getCityDetailsForDropdown.pending, (state) => {
                state.status = 'loading';
            })
            .addCase(getCityDetailsForDropdown.fulfilled, (state, action) => {
                state.status = 'succeeded';
                state.cityDetails = action.payload;
            })
            .addCase(getCityDetailsForDropdown.rejected, (state, action) => {
                state.status = 'failed';
                state.error = action.payload as string;
            });
    },
});

// Export actions
export const { setSelectedCity, updateFilters, resetFilters, setAuthToken } = citiesSlice.actions;

export default citiesSlice.reducer;
