import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { Badge, Button, DialogContainer, Flex, Radio, Panel, SearchInput, Space, tasty, Text, Title, TooltipProvider, ResizablePanel, ClearIcon, } from '@cube-dev/ui-kit';
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, } from 'react';
import { EditOutlined, LoadingOutlined, StarFilled, StarOutlined } from '@ant-design/icons';
import { useDebouncedValue, useFilteredCubes, useEvent, useLocalStorage } from './hooks';
import { useQueryBuilderContext } from './context';
import { EditQueryDialogForm } from './components/EditQueryDialogForm';
import { SidePanelCubeItem } from './components/SidePanelCubeItem';
import { validateQuery } from './utils';
const DEFAULT_SIDEBAR_SIZE = 315;
const RadioButton = tasty(Radio.Button, {
    styles: { flexGrow: 1, placeItems: 'stretch' },
    inputStyles: { textAlign: 'center' },
});
const CountBadge = tasty(Badge, {
    styles: {
        fill: '#purple',
        border: '#purple',
        color: '#white',
        padding: '0 1ow',
    },
});
export function QueryBuilderSidePanel({ defaultSelectedType = 'cubes', customTypeSwitcher = null, showEditQueryButton = true, width, }) {
    const { query, cubes: cubesAndViews = [], selectCube, isQueryEmpty, joinableCubes, isCubeUsed, meta, isVerifying, clearQuery, setQuery, usedCubes, usedMembers, queryStats, members, missingCubes, apiVersion, isMetaLoading, memberViewType, disableSidebarResizing, } = useQueryBuilderContext();
    const contentRef = useRef(null);
    const containerRef = useRef(null);
    const [scrollToCubeName, setScrollToCubeName] = useState(null);
    const [viewMode, setViewMode] = useState(!usedCubes.length ? 'all' : 'query');
    const [isPasteDialogOpen, setIsPasteDialogOpen] = useState(false);
    const [filterString, setFilterString] = useState('');
    const [selectedType, setSelectedType] = useState(defaultSelectedType);
    const [sidebarSize, setSidebarSize] = useLocalStorage('QueryBuilder:Sidebar:size', DEFAULT_SIDEBAR_SIZE);
    const cubes = cubesAndViews.filter((item) => item.type === 'cube');
    const views = cubesAndViews.filter((item) => item.type === 'view');
    const preparedFilterString = filterString.trim().toLowerCase();
    const debouncedFilterString = useDebouncedValue(preparedFilterString, 500);
    const appliedFilterString = preparedFilterString.length < 2 ? '' : debouncedFilterString;
    const cubesOrViews = selectedType === 'cubes' ? cubes : views;
    const allJoinableCubes = selectedType === 'views' && usedCubes.length
        ? cubesOrViews.filter((cube) => usedCubes[0] === cube.name)
        : cubesOrViews.filter((cube) => joinableCubes.includes(cube));
    const [openCubes, setOpenCubes] = useState(new Set());
    useLayoutEffect(() => {
        if (isQueryEmpty) {
            setOpenCubes(cubesOrViews.length === 1 ? new Set([cubesOrViews[0].name]) : new Set());
        }
    }, [cubesOrViews.length, selectedType]);
    const highlightedCubes = appliedFilterString ? usedCubes : [];
    cubesOrViews.sort((a, b) => {
        if (highlightedCubes.includes(a.name) && !highlightedCubes.includes(b.name)) {
            return -1;
        }
        if (!highlightedCubes.includes(a.name) && highlightedCubes.includes(b.name)) {
            return 1;
        }
        return memberViewType === 'name'
            ? a.name.localeCompare(b.name)
            : a.title.localeCompare(b.title);
    });
    // Filtered cubes
    const filteredCubes = useFilteredCubes(appliedFilterString, allJoinableCubes, memberViewType).cubes.map((cube) => cube.name);
    const resetScrollAndContentSize = useCallback(() => {
        if (contentRef?.current) {
            const element = contentRef.current;
            element.scrollTop = 0;
            setTimeout(() => {
                element.scrollTop = 0;
            }, 0);
        }
    }, [contentRef?.current]);
    useEffect(() => {
        resetScrollAndContentSize();
        if (appliedFilterString && viewMode === 'query') {
            setViewMode('all');
        }
    }, [selectedType, appliedFilterString, meta]);
    useEffect(() => {
        const usedView = views.find((cube) => isCubeUsed(cube.name));
        const usedCube = cubes.find((cube) => isCubeUsed(cube.name));
        if (selectedType === 'cubes' && usedView && !usedCube) {
            setSelectedType('views');
            selectCube(usedView?.name);
        }
        else if (selectedType === 'views' && usedCube) {
            setSelectedType('cubes');
        }
    }, [selectedType, query]);
    const switchType = useCallback(async (type) => {
        setSelectedType(type);
    }, [isQueryEmpty]);
    const editQueryButton = useMemo(() => (_jsx(Button, { qa: "EditQueryButton", "aria-label": "Edit Query", type: "primary", size: "small", icon: _jsx(EditOutlined, {}), onPress: () => setIsPasteDialogOpen(true) })), []);
    const typeSwitcher = useMemo(() => {
        return (_jsxs(Space, { qa: "QueryBuilderSwitcher", gap: "1x", children: [editQueryButton, _jsxs(Radio.ButtonGroup, { "aria-label": "Cube type", value: selectedType, styles: { flexGrow: 1 }, onChange: (val) => switchType(val), children: [_jsxs(RadioButton, { qa: "QueryBuilderTab-cubes", value: "cubes", isDisabled: !cubes.length, inputStyles: { placeContent: 'center' }, children: ["Cubes ", _jsx(CountBadge, { radius: "1r", children: cubes.length })] }), _jsxs(RadioButton, { qa: "QueryBuilderTab-views", value: "views", isDisabled: !views.length, inputStyles: { placeContent: 'center' }, children: ["Views ", _jsx(CountBadge, { radius: "1r", children: views.length })] })] })] }));
    }, [selectedType, meta, cubes.length, views.length]);
    const searchInput = useMemo(() => {
        const description = `Search ${selectedType === 'cubes' ? 'cubes' : 'views'} and members`;
        return (_jsx(SearchInput, { isClearable: true, qa: "QueryBuilderSearch", size: "small", "aria-label": description, placeholder: description, value: filterString, onChange: (val) => setFilterString(val) }));
    }, [selectedType, meta, filterString]);
    useEffect(() => {
        if (scrollToCubeName) {
            setTimeout(() => {
                const element = containerRef.current?.querySelector(`[data-qa="CubeButton"][data-qaval="${scrollToCubeName}"]`);
                if (element) {
                    element.scrollIntoView({
                        block: 'start',
                    });
                }
            });
            setScrollToCubeName(null);
        }
    }, [scrollToCubeName]);
    // Close all disabled cubes to avoid layout shift on deselecting member.
    useEffect(() => {
        const currentSize = openCubes.size;
        const allJoinableCubeNames = allJoinableCubes.map((cube) => cube.name);
        openCubes.forEach((cubeName) => {
            if (!allJoinableCubeNames.includes(cubeName) && !missingCubes.includes(cubeName)) {
                openCubes.delete(cubeName);
            }
        });
        if (currentSize !== openCubes.size) {
            setOpenCubes(new Set(openCubes));
        }
    }, [openCubes.size, missingCubes.length, allJoinableCubes.length]);
    function resetState(cubeName) {
        setFilterString('');
        setViewMode('all');
        if (cubeName) {
            setOpenCubes(new Set([cubeName]));
            setScrollToCubeName(cubeName);
        }
    }
    function onCubeToggle(name, isOpen) {
        if (appliedFilterString || viewMode === 'query') {
            resetState(name);
            return;
        }
        if (isOpen) {
            openCubes.add(name);
        }
        else {
            openCubes.delete(name);
        }
        setOpenCubes(new Set(openCubes));
    }
    const onMemberToggle = useEvent((cubeName, memberName) => {
        const isTimeDimension = members.dimensions[memberName]?.type === 'time';
        // Always reset state if we click on time dimension
        if (isTimeDimension || (appliedFilterString && !usedMembers.includes(memberName))) {
            resetState(cubeName);
        }
    });
    const onHierarchyToggle = useEvent((cubeName) => {
        if (appliedFilterString || viewMode === 'query') {
            resetState(cubeName);
        }
    });
    const cubeList = useMemo(() => {
        return (_jsxs(Flex, { gap: "1bw", flow: "column", padding: "0 0 2x 0", children: [missingCubes
                    .filter((cubeName) => (appliedFilterString ? filteredCubes.includes(cubeName) : true))
                    .map((cubeName) => (_jsx(SidePanelCubeItem, { isOpen: openCubes.has(cubeName), filterString: appliedFilterString, cubeName: cubeName, mode: viewMode, rightIcon: "arrow", onHierarchyToggle: onHierarchyToggle, onMemberToggle: (name) => {
                        onMemberToggle(cubeName, name);
                    } }, cubeName))), cubesOrViews
                    .filter((cube) => appliedFilterString
                    ? // If filter is applied, show only filtered cubes
                        filteredCubes.includes(cube.name)
                    : viewMode === 'query'
                        ? // In query mode, show only used cubes
                            usedCubes.includes(cube.name)
                        : true)
                    .map((cube) => (_jsx(SidePanelCubeItem, { isNonJoinable: !allJoinableCubes.includes(cube) && !usedCubes.includes(cube.name), isOpen: openCubes.has(cube.name), filterString: appliedFilterString, cubeName: cube.name, mode: viewMode, rightIcon: isQueryEmpty ? 'arrow' : 'plus', onToggle: (isOpen) => {
                        onCubeToggle(cube.name, isOpen);
                    }, onMemberToggle: (name) => {
                        onMemberToggle(cube.name, name);
                    }, onHierarchyToggle: onHierarchyToggle }, cube.name)))] }));
    }, [
        viewMode,
        queryStats,
        [...openCubes.values()].join(),
        appliedFilterString,
        memberViewType,
        selectedType,
    ]);
    const onApplyQuery = useCallback(async (query) => {
        try {
            const validatedQuery = validateQuery(query);
            setQuery(validatedQuery);
        }
        catch (e) {
            throw 'Invalid query';
        }
    }, []);
    useEffect(() => {
        if (viewMode === 'query') {
            if (filterString) {
                setFilterString('');
            }
            setOpenCubes(new Set(usedCubes));
            setScrollToCubeName(usedCubes[0]);
            if (isQueryEmpty) {
                setViewMode('all');
            }
        }
    }, [viewMode, isQueryEmpty]);
    const topBar = useMemo(() => {
        return (_jsxs(Space, { placeContent: "space-between", gap: "1x", children: [_jsxs(Space, { gap: "1x", children: [showEditQueryButton ? editQueryButton : null, !usedCubes.length ? (_jsx(Title, { preset: "h6", children: "All members" })) : (_jsx(TooltipProvider, { title: 'Toggle between all members and only those that are used in the query', placement: "top", children: _jsx(Button, { qa: "ToggleMembersButton", qaVal: viewMode === 'all' ? 'all' : 'used', type: viewMode === 'all' ? 'outline' : 'primary', size: "small", icon: viewMode === 'all' ? _jsx(StarOutlined, {}) : _jsx(StarFilled, {}), onPress: () => setViewMode(viewMode === 'all' ? 'query' : 'all'), children: viewMode === 'all' ? 'All members' : 'Used only' }) })), isVerifying || isMetaLoading ? _jsx(LoadingOutlined, {}) : null] }), _jsx(Space, { gap: ".5x", children: _jsx(TooltipProvider, { title: "Reset the query", children: _jsx(Button, { qa: "ResetQuery", "aria-label": "Reset the query", size: "small", type: "secondary", theme: "danger", icon: _jsx(ClearIcon, {}), onPress: () => {
                                clearQuery();
                                setOpenCubes(cubesOrViews.length === 1 ? new Set([cubesOrViews[0].name]) : new Set());
                                resetScrollAndContentSize();
                            }, children: "Reset" }) }) })] }));
    }, [viewMode, isQueryEmpty, isMetaLoading, usedMembers.length, appliedFilterString, isVerifying]);
    const content = (_jsxs(_Fragment, { children: [_jsx(DialogContainer, { isOpen: isPasteDialogOpen, onDismiss: () => setIsPasteDialogOpen(false), children: _jsx(EditQueryDialogForm, { query: query, defaultType: 'json', apiVersion: apiVersion, onSubmit: onApplyQuery }) }), !usedCubes.length ? _jsx(_Fragment, { children: customTypeSwitcher ?? typeSwitcher }) : topBar, searchInput, appliedFilterString && !filteredCubes.length ? (_jsx(Space, { placeContent: "space-between", placeItems: "baseline", border: "top", margin: "0 -1x", padding: "1x 1x 0 1x", children: !filteredCubes.length ? (_jsxs(Text, { preset: "c2", children: ["No ", selectedType === 'cubes' ? 'cubes' : 'views', " or members found"] })) : null })) : undefined, _jsx(Panel, { margin: "0 -1x", border: "top", flexGrow: 1, children: cubeList })] }));
    return disableSidebarResizing ? (_jsx(Panel, { ref: containerRef, isFlex: true, qa: "QueryBuilderSidePanel", flow: "column", padding: "1x 1x 0 1x", gap: "1x", border: "1ow right", width: width ?? `max ${DEFAULT_SIDEBAR_SIZE}px`, innerStyles: {
            overflowX: 'clip',
        }, children: content }, "disabled-siderbar-resizing")) : (_jsx(ResizablePanel, { ref: containerRef, isFlex: true, qa: "QueryBuilderSidePanel", flow: "column", direction: "right", size: disableSidebarResizing ? DEFAULT_SIDEBAR_SIZE : sidebarSize, isDisabled: disableSidebarResizing, minSize: DEFAULT_SIDEBAR_SIZE, maxSize: "35%", padding: "1x 1x 0 1x", gap: "1x", innerStyles: {
            overflowX: 'clip',
        }, onSizeChange: setSidebarSize, children: content }, "resizable-siderbar"));
}
//# sourceMappingURL=QueryBuilderSidePanel.js.map