import React, { useState, useEffect, useRef, useLayoutEffect } from 'react';
import { createPortal } from 'react-dom';
import { Bell } from 'lucide-react';
import { COMMON_FIELDS } from '@nexuscrm/generated-schema';
import { notificationsAPI, type HostNotification } from '@nexuscrm/host-sdk';
import { useNavigate } from 'react-router-dom';
import { NOTIFICATION_POLL_INTERVAL_MS } from './notificationTiming';
import { Logger } from '../../core/services/Logger';

// NotificationCenter needs user context, so we use an inner component
import { useRuntime } from '@nexuscrm/host-sdk';

export const NotificationCenter: React.FC = () => {
    return <NotificationCenterInner />;
};

function formatNotificationAge(value: string): string {
    const timestamp = new Date(value).getTime();
    if (!Number.isFinite(timestamp)) {
        return '';
    }
    const seconds = Math.max(0, Math.floor((Date.now() - timestamp) / 1000));
    if (seconds < 60) {
        return 'just now';
    }
    const minutes = Math.floor(seconds / 60);
    if (minutes < 60) {
        return `${minutes}m ago`;
    }
    const hours = Math.floor(minutes / 60);
    if (hours < 24) {
        return `${hours}h ago`;
    }
    const days = Math.floor(hours / 24);
    return `${days}d ago`;
}

const NotificationCenterInner: React.FC = () => {
    const { user } = useRuntime();
    const [notifications, setNotifications] = useState<HostNotification[]>([]);
    const [isOpen, setIsOpen] = useState(false);
    const buttonRef = useRef<HTMLButtonElement>(null);
    const dropdownRef = useRef<HTMLDivElement>(null);
    const [dropdownPos, setDropdownPos] = useState({ top: 0, right: 0 });
    const navigate = useNavigate();

    const shouldPoll = true;

    // Position the dropdown relative to the bell button
    const updatePosition = React.useCallback(() => {
        if (buttonRef.current && isOpen) {
            const rect = buttonRef.current.getBoundingClientRect();
            setDropdownPos({
                top: rect.bottom + 8,
                right: window.innerWidth - rect.right,
            });
        }
    }, [isOpen]);

    useLayoutEffect(() => {
        if (isOpen) {
            updatePosition();
            window.addEventListener('resize', updatePosition);
            window.addEventListener('scroll', updatePosition, true);
        }
        return () => {
            window.removeEventListener('resize', updatePosition);
            window.removeEventListener('scroll', updatePosition, true);
        };
    }, [isOpen, updatePosition]);

    const loadNotifications = React.useCallback(async () => {
        if (!user?.[COMMON_FIELDS.ID]) return;
        try {
            const data = await notificationsAPI.list();
            if (data && Array.isArray(data.notifications)) {
                setNotifications(data.notifications);
            }
        } catch (error: unknown) {
            Logger.warn('[NotificationCenter] Failed to load notifications', {}, error);
        }
    }, [user]);

    useEffect(() => {
        if (user?.[COMMON_FIELDS.ID] && shouldPoll) {
            loadNotifications();
            const interval = setInterval(loadNotifications, NOTIFICATION_POLL_INTERVAL_MS);
            return () => clearInterval(interval);
        }
    }, [user, loadNotifications, shouldPoll]);

    const unreadCount = notifications.filter(n => n.unread).length;

    const handleMarkAsRead = async (id: string) => {
        try {
            // Optimistic update
            setNotifications(prev => prev.map(n => n.id === id ? { ...n, unread: false } : n));
            await notificationsAPI.markAsRead(id);
        } catch (err: unknown) {
            Logger.error('[NotificationCenter] Failed to mark notification as read', {}, err);
        }
    };

    const handleMarkAllRead = async () => {
        const unread = notifications.filter(n => n.unread);
        // Optimistic
        setNotifications(prev => prev.map(n => ({ ...n, unread: false })));

        if (unread.length > 0) {
            await notificationsAPI.markAllAsRead();
        }
    };

    // Close on click outside
    useEffect(() => {
        const handleClickOutside = (event: MouseEvent) => {
            if (
                dropdownRef.current && !dropdownRef.current.contains(event.target as Node) &&
                buttonRef.current && !buttonRef.current.contains(event.target as Node)
            ) {
                setIsOpen(false);
            }
        };
        if (isOpen) document.addEventListener('mousedown', handleClickOutside);
        return () => document.removeEventListener('mousedown', handleClickOutside);
    }, [isOpen]);

    const dropdownContent = (
        <div
            ref={dropdownRef}
            className="fixed w-80 bg-white border border-slate-200 rounded-lg shadow-xl z-[9999] max-h-[400px] flex flex-col"
            style={{ top: dropdownPos.top, right: dropdownPos.right }}
        >
            <div className="px-4 py-3 border-b border-slate-100 flex justify-between items-center shrink-0">
                <h3 className="font-semibold text-slate-900">Notifications</h3>
                {unreadCount > 0 && (
                    <button onClick={handleMarkAllRead} className="text-xs text-blue-600 hover:text-blue-700 font-medium">
                        Mark all as read
                    </button>
                )}
            </div>
            <div className="overflow-y-auto flex-1">
                {notifications.length === 0 ? (
                    <div className="p-8 text-center text-slate-500 text-sm">
                        No notifications
                    </div>
                ) : (
                    <div>
                        {notifications.map(n => (
                            <div
                                key={n.id}
                                className={`px-4 py-3 border-b border-slate-50 hover:bg-slate-50 transition-colors cursor-pointer ${n.unread ? 'bg-blue-50/30' : ''}`}
                                onClick={() => {
                                    if (n.url) {
                                        navigate(n.url);
                                        setIsOpen(false);
                                    }
                                    if (n.unread) handleMarkAsRead(n.id);
                                }}
                            >
                                <div className="flex gap-3">
                                    <div className="flex-1">
                                        <p className={`text-sm ${n.unread ? 'font-semibold text-slate-900' : 'text-slate-700'}`}>
                                            {n.messageTitle}
                                        </p>
                                        <p className="text-xs text-slate-500 mt-1 line-clamp-2">{n.messageBody}</p>
                                        <p className="text-[10px] text-slate-400 mt-1">
                                            {n.createdDate ? formatNotificationAge(n.createdDate) : ''}
                                        </p>
                                    </div>
                                    {n.unread && (
                                        <div className="mt-1">
                                            <div className="w-2 h-2 rounded-full bg-blue-500" />
                                        </div>
                                    )}
                                </div>
                            </div>
                        ))}
                    </div>
                )}
            </div>
        </div>
    );

    return (
        <div className="relative">
            <button
                ref={buttonRef}
                onClick={() => setIsOpen(!isOpen)}
                className="p-2 text-slate-500 hover:bg-slate-100 rounded-full transition-colors relative"
            >
                <Bell size={20} />
                {unreadCount > 0 && (
                    <span className="absolute top-2 right-2 w-2 h-2 bg-red-500 rounded-full border-2 border-white"></span>
                )}
            </button>

            {isOpen && createPortal(dropdownContent, document.body)}
        </div>
    );
};
