import React, { useCallback, useEffect, useRef, useState } from 'react';
import { __ } from '@wordpress/i18n';
import { head, isEmpty, pathOr } from 'ramda';
import SockJS from 'sockjs-client';
import { Stomp } from '@stomp/stompjs';

// store
import { storeGet, useStoreValue } from '../../store';

// api
import NotificationService from '../../service/notification-service';

// tools
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';

// components
import { Badge } from 'primereact/badge';
import { Sidebar } from 'primereact/sidebar';
import { TabPanel, TabView } from 'primereact/tabview';
import NotificationItem from './components/NotificationItem';
import NotificationItemChosen from './components/NotificationItemChosen';
import PaginatorBasic from '../PaginatorBasic';

const socketUrl = process.env.REACT_APP_API_ADDRESS_WS;

const NotificationsSidebar = () => {
    const chosenCompanyId = useStoreValue('chosenCompanyId');
    const userData = useStoreValue('userData');
    const [activeIndex, setActiveIndex] = useState(0);
    const [loading, setLoading] = useState(false);
    const [notificationsVisible, setNotificationsVisible] = useState(false);
    const [notifications, setNotifications] = useState([]);
    const [notificationsRead, setNotificationsRead] = useState([]);
    const [chosenMsg, setChosenMsg] = useState({});
    const socket = useRef(null);
    const stomp = useRef(null);
    const [currentSubscription, setCurrentSubscription] = useState(null);
    const [isConnected, setIsConnected] = useState(false);
    const [currentPage, setCurrentPage] = useState(1);
    const [totalRecordsNum, setTotalRecordsNum] = useState(0);
    const [totalPagesNum, setTotalPagesNum] = useState(0);
    const perPage = 10;

    // Handle tab change
    const handleTabChange = (e) => {
        if (e.index === activeIndex) {
            return
        }
        setTotalRecordsNum(0);
        setTotalPagesNum(0);
        setChosenMsg({});
        setActiveIndex(e.index);
        setCurrentPage(1);
    };

    const chooseNotification = (id) => {
        const properItems = activeIndex === 0 ? notifications : notificationsRead;
        const chosen = head(properItems.filter(o => o.id === id));
        if (chosen) {
            setChosenMsg(chosen);
        }
    }

    const closeChosenMsg = () => {
        setChosenMsg({});
    }

    const getPaginationQuery = (status = 'UNREAD', curPage = 1) => {
        return {
            'globalFilters': {
                'page': curPage,
                'limit': perPage,
                'sortBy': {
                    'columnName': 'id',
                    'sortDesc': true
                }
            },
            'status': [
                status
            ]
        }
    }

    const fetchMessages = useCallback((status = 'UNREAD') => {
        const chosenCompanyId = storeGet('chosenCompanyId');
        const userData = storeGet('userData');
        const role = pathOr('', ['role', 'roleType'], userData);
        const bodyParams = getPaginationQuery(status, currentPage);

        if (currentSubscription) {
            currentSubscription.unsubscribe();
            setCurrentSubscription(null);
        }

        if (userData.id && chosenCompanyId !== 0 && role === 'ROLE_BENEFICIARY') {
            setLoading(true);
            NotificationService.getNotificationsByCompanyIdPagination(
                userData.id,
                chosenCompanyId,
                bodyParams,
                status === 'UNREAD' ? getNotificationsPagi : getNotificationsReadPagi,
                errGetNotifications
            );
            if (isConnected && socket.current) {
                subscribeTo(`/topic/notifications_user_${userData.id}_company_${chosenCompanyId}`)
            }
        } else if (userData.id && role !== 'ROLE_BENEFICIARY') {
            setLoading(true);
            NotificationService.getNotificationsPagination(
                userData.id,
                bodyParams,
                status === 'UNREAD' ? getNotificationsPagi : getNotificationsReadPagi,
                errGetNotifications
            );
            if (isConnected && socket.current) {
                subscribeTo(`/topic/notifications_user_${userData.id}`)
            }
        }
    }, [currentPage]);

    const getNotificationsPagi = (resp) => {
        if (resp.status === 'SUCCESS') {
            const { body, totalRecords, currentPage, totalPages } = resp.data;
            setNotifications(body);
            setTotalRecordsNum(totalRecords);
            setTotalPagesNum(totalPages);
            if (currentPage > totalPages) {
                setCurrentPage(totalPages);
            }
        }
        set404FromErrorResponse(resp);
        setLoading(false);
    }

    const getNotificationsReadPagi = (resp) => {
        if (resp.status === 'SUCCESS') {
            const { body, totalRecords, currentPage, totalPages } = resp.data;
            setNotificationsRead(body);
            setTotalRecordsNum(totalRecords);
            setTotalPagesNum(totalPages);
            if (currentPage > totalPages) {
                setCurrentPage(totalPages);
            }
        }
        set404FromErrorResponse(resp);
        setLoading(false);
    }

    const errGetNotifications = (resp) => {
        set404FromErrorResponse(resp);
        setLoading(false);
    }

    const makeNotificationRead = (id) => {
        NotificationService.notificationMakeRead(id, makeReadCallback, makeReadErrorCallback)
    }

    const makeReadCallback = (resp) => {
        if (resp.status === 'SUCCESS') {
            if (0 === activeIndex) {
                const msgs = notifications.map(o => o.id === resp.data.id ? resp.data : o);
                setNotifications(msgs);
            } else {
                const msgs = notificationsRead.map(o => o.id === resp.data.id ? resp.data : o);
                setNotificationsRead(msgs);
            }
            setTotalRecordsNum(totalRecordsNum - 1);
        }
        set404FromErrorResponse(resp);
    }

    const makeReadErrorCallback = (resp) => {
        set404FromErrorResponse(resp);
    }

    const connectWebSocket = () => {
        // BFLOWS: consenti di disabilitare WSS via env (sandbox senza RabbitMQ)
        if (process.env.REACT_APP_ENABLE_WEBSOCKET === '0') {
            return;
        }
        socket.current = new SockJS(socketUrl, null, {
                transports: [
                    'websocket',
                    'xhr-streaming',
                    'xhr-polling'
                ]
            }
        );
        stomp.current = Stomp.over(socket.current);

        stomp.current.configure({
            debug: function (str) {
                //console.log(str);
            },
            reconnectDelay: 5000,
            heartbeatIncoming: 20000,
            heartbeatOutgoing: 20000
        });

        stomp.current.connect(
            {},
            () => {
                //console.log('Websocket connected');
                setIsConnected(true);
            },
            (error) => {
                //console.error('WebSocket Connection Error:', error);
                setIsConnected(false);
                setTimeout(connectWebSocket, 5000);
            }
        );
    };

    const subscribeTo = (topic) => {
        const subscription = stomp.current.subscribe(
            topic,
            (message) => {
                try {
                    const notification = JSON.parse(message.body);
                    setNotifications(prev => [notification, ...prev]);
                } catch (error) {
                    console.error('Error parsing notification:', error);
                }
            }
        );

        setCurrentSubscription(subscription);
    }

    const onPageChange = (num) => {
        setCurrentPage(num);
    };

    useEffect(() => {
        if (userData && userData.id) {
            fetchMessages();
        }
    }, [chosenCompanyId, userData.id, isConnected]);

    useEffect(() => {
        if (0 === activeIndex) {
            fetchMessages();
        } else {
            fetchMessages('READ');
        }
    }, [currentPage, activeIndex]);

    useEffect(() => {
        connectWebSocket();

        return () => {
            if (currentSubscription) {
                currentSubscription.unsubscribe();
                setCurrentSubscription(null);
            }

            if (stomp.current) {
                stomp.current.disconnect(() => {
                    //console.log('WebSocket Disconnected');
                });
            }
        };
    }, []);

    return (
        <>
            <i className="pi pi-bell p-overlay-badge topBar__icon notificationsIcon"
               onClick={() => setNotificationsVisible(true)}>
                <Badge value={totalRecordsNum}></Badge>
            </i>
            <Sidebar
                className="notificationsSidebar"
                position="left"
                visible={notificationsVisible}
                onHide={() => setNotificationsVisible(false)}>
                <TabView activeIndex={activeIndex} onTabChange={handleTabChange}>
                    <TabPanel header={__('Da leggere', 'gepafin')}>
                        {loading
                            ? <div className="notificationsSidebar__loading">
                                <i className="pi pi-spin pi-spinner" style={{ fontSize: '2rem' }}></i>
                            </div>
                            : !isEmpty(chosenMsg)
                                ? <NotificationItemChosen
                                    item={chosenMsg}
                                    closeFn={closeChosenMsg}
                                    markReadFn={makeNotificationRead}/>
                                : (notifications.length > 0
                                    ? <>
                                        <ul className="notificationsSidebar__list">
                                            {notifications.map(o => <NotificationItem
                                                key={o.id}
                                                item={o}
                                                clickFn={chooseNotification}/>)}
                                        </ul>
                                        <PaginatorBasic
                                            totalPages={totalPagesNum}
                                            currentPage={currentPage}
                                            clickFn={onPageChange}
                                        />
                                    </>
                                    : <div className="notificationsSidebar__loading">
                                        <i className="pi pi-megaphone" style={{ fontSize: '2rem' }}></i>
                                        {__('Vuoto', 'gepafin')}
                                    </div>)}
                    </TabPanel>
                    <TabPanel header={__('Letti', 'gepafin')}>
                        {loading
                            ? <div className="notificationsSidebar__loading">
                                <i className="pi pi-spin pi-spinner" style={{ fontSize: '2rem' }}></i>
                            </div>
                            : !isEmpty(chosenMsg)
                                ? <NotificationItemChosen
                                    item={chosenMsg}
                                    closeFn={closeChosenMsg}
                                    markReadFn={makeNotificationRead}/>
                                : (notificationsRead.length > 0
                                    ? <>
                                        <ul className="notificationsSidebar__list">
                                            {notificationsRead.map(o => <NotificationItem
                                                key={o.id}
                                                item={o}
                                                clickFn={chooseNotification}/>)}
                                        </ul>
                                        <PaginatorBasic
                                            totalPages={totalPagesNum}
                                            currentPage={currentPage}
                                            clickFn={onPageChange}
                                        />
                                    </>
                                    :
                                    <div className="notificationsSidebar__loading">
                                        <i className="pi pi-megaphone" style={{ fontSize: '2rem' }}></i>
                                        {__('Vuoto', 'gepafin')}
                                    </div>)}
                    </TabPanel>
                </TabView>
            </Sidebar>
        </>
    )
}

export default NotificationsSidebar;
