import {
    createContext,
    useCallback,
    useContext,
    useMemo,
    useState,
    type CSSProperties,
    type ReactNode,
} from 'react';
import { isDesktopViewport, useSidePanelMachine } from '../panels/useSidePanelMachine';

const RIGHT_SIDEBAR_WIDTH_KEY = 'authRightSidebarWidth';
const RIGHT_SIDEBAR_DEFAULT_WIDTH = 320;
const RIGHT_SIDEBAR_MIN_WIDTH = 260;
const RIGHT_SIDEBAR_MAX_WIDTH = 480;

export type RightSidebarSizing = {
    defaultWidth?: number;
    minWidth?: number;
    maxWidth?: number;
};

export type RightSidebarContent = {
    title: string;
    content: ReactNode;
    ariaLabel?: string;
};

export type RightSidebarStyle = CSSProperties & {
    '--auth-right-sidebar-width': string;
};

type RightSidebarContextValue = {
    isOpen: boolean;
    content: RightSidebarContent | null;
    openSidebar: (content?: RightSidebarContent) => void;
    closeSidebar: () => void;
    toggleSidebar: (content?: RightSidebarContent) => void;
    setSidebarContent: (content: RightSidebarContent | null) => void;
    desktopSidebarStyle: RightSidebarStyle;
    startResize: ReturnType<typeof useSidePanelMachine>['startResize'];
};

type RightSidebarProviderProps = {
    children: ReactNode;
    closeOnPathname?: string;
    onMobileOpenRequest?: () => void;
    sizing?: RightSidebarSizing;
};

const RightSidebarContext = createContext<RightSidebarContextValue | undefined>(undefined);

function readSizingValue(value: number | undefined, fallback: number): number {
    if (!Number.isFinite(value) || value == null || value <= 0) {
        return fallback;
    }

    return value;
}

function resolveRightSidebarSizing(sizing: RightSidebarSizing | undefined) {
    const requestedMinWidth = readSizingValue(sizing?.minWidth, RIGHT_SIDEBAR_MIN_WIDTH);
    const requestedMaxWidth = readSizingValue(sizing?.maxWidth, RIGHT_SIDEBAR_MAX_WIDTH);
    const minWidth = Math.min(requestedMinWidth, requestedMaxWidth);
    const maxWidth = Math.max(requestedMinWidth, requestedMaxWidth);
    const requestedDefaultWidth = readSizingValue(
        sizing?.defaultWidth,
        RIGHT_SIDEBAR_DEFAULT_WIDTH,
    );
    const defaultWidth = Math.min(maxWidth, Math.max(minWidth, requestedDefaultWidth));

    return {
        defaultWidth,
        minWidth,
        maxWidth,
    };
}

export function RightSidebarProvider({
    children,
    closeOnPathname,
    onMobileOpenRequest,
    sizing,
}: Readonly<RightSidebarProviderProps>) {
    const { defaultWidth, minWidth, maxWidth } = resolveRightSidebarSizing(sizing);
    const [isOpen, setIsOpen] = useState(false);
    const [content, setContent] = useState<RightSidebarContent | null>(null);

    const closeSidebar = useCallback(() => {
        setIsOpen(false);
        setContent(null);
    }, []);

    const setSidebarContent = useCallback((nextContent: RightSidebarContent | null) => {
        setContent(nextContent);
    }, []);

    const openSidebar = useCallback(
        (nextContent?: RightSidebarContent) => {
            const resolvedContent = nextContent ?? content;
            if (!resolvedContent) {
                return;
            }

            if (nextContent) {
                setContent(nextContent);
            }
            if (!isDesktopViewport()) {
                onMobileOpenRequest?.();
            }
            setIsOpen(true);
        },
        [content, onMobileOpenRequest],
    );

    const toggleSidebar = useCallback(
        (nextContent?: RightSidebarContent) => {
            if (isOpen) {
                closeSidebar();
                return;
            }

            openSidebar(nextContent);
        },
        [isOpen, closeSidebar, openSidebar],
    );

    const { width, startResize } = useSidePanelMachine({
        storageKey: RIGHT_SIDEBAR_WIDTH_KEY,
        defaultWidth,
        minWidth,
        maxWidth,
        resizeAxis: 'from-right',
        resizingBodyClass: 'auth-right-sidebar-resizing',
        isOpen,
        canResize: isOpen,
        shouldPersistWidth: true,
        closeOnPathname,
        onCloseOnPathname: closeSidebar,
        onEscape: closeSidebar,
    });

    const desktopSidebarStyle = useMemo<RightSidebarStyle>(
        () => ({
            '--auth-right-sidebar-width': `${width}px`,
        }),
        [width],
    );

    const value = useMemo<RightSidebarContextValue>(
        () => ({
            isOpen,
            content,
            openSidebar,
            closeSidebar,
            toggleSidebar,
            setSidebarContent,
            desktopSidebarStyle,
            startResize,
        }),
        [
            isOpen,
            content,
            openSidebar,
            closeSidebar,
            toggleSidebar,
            setSidebarContent,
            desktopSidebarStyle,
            startResize,
        ],
    );

    return <RightSidebarContext.Provider value={value}>{children}</RightSidebarContext.Provider>;
}

export function useRightSidebar() {
    const ctx = useContext(RightSidebarContext);
    if (!ctx) {
        throw new Error('useRightSidebar must be used within RightSidebarProvider');
    }
    return ctx;
}
