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

export type NotificationItem = {
    id: number;
    title: string;
    message: string;
    time?: string;
    read?: boolean;
    created_at?: string;
    is_read?: boolean;
    data?: {
        orderId?: string | number;
        type?: string;
        [key: string]: any;
    };
};

interface NotificationsState {
    items: NotificationItem[];
    page: number;
    limit: number;
    total: number | null;
    unreadCount: number;
    hasMore: boolean;
    isLoading: boolean;
    error: string | null;
}

export const notificationsInitialState: NotificationsState = {
    items: [],
    page: 1,
    limit: 5,
    total: null,
    unreadCount: 0,
    hasMore: true,
    isLoading: false,
    error: null,
};

export const fetchNotifications = createAsyncThunk(
    'notifications/fetch',
    async ({ page, limit, isRead }: { page: number; limit: number; isRead?: boolean }, { rejectWithValue }) => {
        try {
            const skip = Math.max(0, (page - 1) * limit);
            const params: any = {
                skip,
                limit,
            };

            // Add is_read filter only when explicitly filtering for unread
            if (isRead === false) {
                params.is_read = false;
            }

            const response = await api.get('/notification', { params });
            return response.data;
        } catch (error: any) {
            if (error?.response?.data?.message) return rejectWithValue(error.response.data.message);
            if (error?.message) return rejectWithValue(error.message);
            return rejectWithValue(messages.toasts.error.failed_to_fetch_notifications);
        }
    },
);

export const markAsRead = createAsyncThunk('notifications/markAsRead', async (notificationId: number, { rejectWithValue }) => {
    try {
        const response = await api.post(`/notification/${notificationId}/mark-as-read`);
        return { id: notificationId, data: response.data };
    } catch (error: any) {
        if (error?.response?.data?.message) return rejectWithValue(error.response.data.message);
        if (error?.message) return rejectWithValue(error.message);
        return rejectWithValue(messages.toasts.error.failed_to_mark_notification_read);
    }
});

const notificationsSlice = createSlice({
    name: 'notifications',
    initialState: notificationsInitialState,
    reducers: {
        setPage(state, action) {
            state.page = action.payload;
        },
        setLimit(state, action) {
            state.limit = action.payload;
        },
        clearNotifications(state) {
            state.items = [];
            state.total = null;
            state.page = 1;
            state.hasMore = true;
        },
        markNotificationAsRead(state, action) {
            const notificationId = action.payload;
            const notification = state.items.find((item) => item.id === notificationId);
            if (notification) {
                notification.is_read = true;
                notification.read = true;
            }
            // Decrement unread count
            if (state.unreadCount > 0) {
                state.unreadCount -= 1;
            }
        },
    },
    extraReducers: (builder) => {
        builder
            .addCase(fetchNotifications.pending, (state) => {
                state.isLoading = true;
                state.error = null;
            })
            .addCase(fetchNotifications.fulfilled, (state, action: any) => {
                state.isLoading = false;
                const dataObj = action.payload?.data ?? {};
                const list = Array.isArray(dataObj?.data) ? (dataObj.data as NotificationItem[]) : [];
                const newItems = list;

                if (state.page === 1) {
                    state.items = newItems;
                } else {
                    const existingIds = new Set(state.items.map((item) => item.id));
                    const uniqueNewItems = newItems.filter((item) => !existingIds.has(item.id));
                    state.items = [...state.items, ...uniqueNewItems];
                }

                if (typeof dataObj?.unreadCount === 'number') {
                    state.unreadCount = dataObj.unreadCount as number;
                }

                if (typeof dataObj?.pagination?.total === 'number') {
                    state.total = dataObj.pagination.total as number;
                } else if (typeof dataObj?.count === 'number') {
                    state.total = dataObj.count as number;
                }

                const currentPage =
                    typeof dataObj?.pagination?.page === 'number' ? (dataObj.pagination.page as number) : state.page;
                const totalPages =
                    typeof dataObj?.pagination?.totalPages === 'number' ? (dataObj.pagination.totalPages as number) : undefined;
                if (typeof totalPages === 'number') {
                    state.hasMore = currentPage < totalPages;
                } else {
                    state.hasMore = Array.isArray(newItems) && newItems.length === state.limit;
                }
            })
            .addCase(fetchNotifications.rejected, (state, action) => {
                state.isLoading = false;
                state.error = (action.payload as string) || messages.toasts.error.failed_to_fetch_notifications;
            })
            .addCase(markAsRead.fulfilled, (state, action) => {
                const notificationId = action.payload.id;
                const notification = state.items.find((item) => item.id === notificationId);
                if (notification && !notification.is_read) {
                    notification.is_read = true;
                    notification.read = true;
                    // Decrement unread count
                    if (state.unreadCount > 0) {
                        state.unreadCount -= 1;
                    }
                }
            });
    },
});

export const { setPage, setLimit, clearNotifications, markNotificationAsRead } = notificationsSlice.actions;
export default notificationsSlice.reducer;
