import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { Block, Button, ComboBox, Menu, MenuTrigger, PlusIcon, Select, tasty, useToastsApi, } from '@cube-dev/ui-kit';
import { useEffect, useMemo, useRef, useState } from 'react';
import { useQueryBuilderContext } from '../context';
import { useEvent } from '../hooks';
import { MemberLabel } from './MemberLabel';
const AddFilterButton = tasty(Button, {
    qa: 'AddFilterButton',
    'aria-label': 'Add a new filter',
    size: 'small',
    type: 'secondary',
    icon: _jsx(PlusIcon, {}),
    width: {
        '': '3x',
        label: 'auto',
    },
});
export function AddFilterInput(props) {
    const { onAdd, onDateRangeAdd, onSegmentAdd, isCompact, hasLabel } = props;
    const [mode, setMode] = useState(null);
    const { toast } = useToastsApi();
    const inputRef = useRef(null);
    const { query, joinableMembers, usedCubes, cubes, memberViewType, dateRanges: queryDateRanges, } = useQueryBuilderContext();
    const [members, dimensions, measures, dateRanges, segments, nameToMemberType] = useMemo(() => {
        // Sort members by cube name and used status
        const sort = (a, b) => {
            const aCubeName = usedCubes.find((cubeName) => cubeName === a.name.split('.')[0]);
            const bCubeName = usedCubes.find((cubeName) => cubeName === b.name.split('.')[0]);
            if (aCubeName || bCubeName) {
                if (aCubeName && bCubeName) {
                    return aCubeName.localeCompare(bCubeName);
                }
                else {
                    return aCubeName && !bCubeName ? -1 : 1;
                }
            }
            return a.name.localeCompare(b.name);
        };
        const members = [
            ...Object.values(joinableMembers.dimensions).sort(sort),
            ...Object.values(joinableMembers.measures).sort(sort),
            ...Object.values(joinableMembers.segments).sort(sort),
        ];
        const nameToMemberType = members.reduce((acc, member) => {
            acc[member.name] = ['dimension', 'measure', 'segment'][[
                !!joinableMembers.dimensions[member.name],
                !!joinableMembers.measures[member.name],
                !!joinableMembers.segments[member.name],
            ].indexOf(true)];
            return acc;
        }, {});
        const dimensions = members.filter((member) => {
            return nameToMemberType[member.name] === 'dimension';
        });
        const measures = members.filter((member) => {
            return nameToMemberType[member.name] === 'measure';
        });
        const segments = members
            .filter((member) => {
            return nameToMemberType[member.name] === 'segment';
        })
            .filter((member) => {
            return !query.segments?.includes(member.name);
        });
        const dateRanges = members
            .filter((member) => nameToMemberType[member.name] === 'dimension' &&
            member.type === 'time')
            .filter((member) => {
            return !queryDateRanges.list.includes(member.name);
        });
        return [
            members,
            dimensions,
            measures,
            dateRanges,
            segments,
            nameToMemberType,
        ];
    }, [
        JSON.stringify(joinableMembers),
        queryDateRanges.list.join(),
        query.segments?.join(),
        usedCubes.length,
    ]);
    const shownMembers = useMemo(() => {
        let shownMembers;
        switch (mode) {
            case 'measure':
                shownMembers = measures;
                break;
            case 'dimension':
                shownMembers = dimensions;
                break;
            case 'segment':
                shownMembers = segments;
                break;
            case 'dateRange':
                shownMembers = dateRanges;
                break;
            default:
                shownMembers = [];
        }
        return shownMembers;
    }, [members, mode]);
    const onAction = useEvent((key) => {
        if (key === 'and') {
            onAdd({ and: [] });
            return;
        }
        if (key === 'or') {
            onAdd({ or: [] });
            return;
        }
        setMode(key);
    });
    const onFilterAdd = useEvent((key) => {
        if (!key) {
            return;
        }
        if (mode === 'dateRange') {
            onDateRangeAdd?.(key);
        }
        else if (mode === 'segment') {
            onSegmentAdd?.(key);
        }
        else {
            onAdd({ member: key, operator: 'equals', values: [] });
        }
    });
    const items = useMemo(() => {
        const items = [
            { value: 'dimension', label: 'Filter by Dimension' },
            { value: 'measure', label: 'Filter by Measure' },
        ];
        if (onSegmentAdd) {
            items.push({ value: 'segment', label: 'Filter by Segment' });
        }
        if (onDateRangeAdd) {
            items.push({ value: 'dateRange', label: 'Filter by Date Range' });
        }
        items.push({ value: 'and', label: 'AND Branch' }, { value: 'or', label: 'OR Branch' });
        return items;
    }, [onDateRangeAdd, onSegmentAdd]);
    const disabledKeys = useMemo(() => {
        const disabledKeys = [];
        if (!dateRanges.length) {
            disabledKeys.push('dateRange');
        }
        if (!dimensions.length) {
            disabledKeys.push('dimension');
        }
        if (!measures.length) {
            disabledKeys.push('measure');
        }
        if (!segments.length) {
            disabledKeys.push('segment');
        }
        return disabledKeys;
    }, [dateRanges.length, dimensions.length, measures.length, segments.length]);
    useEffect(() => {
        if (mode && !shownMembers.length && !['or', 'and'].includes(mode)) {
            const title = {
                measure: 'filter',
                dimension: 'filter',
                segment: 'segment',
                dateRange: 'date range',
            }[mode];
            toast.attention({
                header: `Unable to add new ${title}`,
                description: 'No available members',
            });
            setMode(null);
        }
    }, [shownMembers.length, mode]);
    // Hack to focus input after it's shown
    // autoFocus and menuTrigger="focus" don't work together
    useEffect(() => {
        setTimeout(() => {
            inputRef.current?.focus();
        }, 100);
    }, [inputRef.current, mode]);
    return (_jsx(Block, { children: !mode ? (_jsxs(MenuTrigger, { children: [_jsx(AddFilterButton, { mods: { label: hasLabel }, children: hasLabel ? 'Add' : undefined }), _jsx(Menu, { items: items, disabledKeys: disabledKeys, onAction: onAction, children: items.map((item) => (_jsx(Menu.Item, { textValue: item.value, children: item.label }, item.value))) })] })) : (_jsx(ComboBox, { qa: "AddFilterInput", inputRef: inputRef, menuTrigger: "focus", size: "small", width: "50x", placeholder: items.find((item) => item.value === mode)?.label, listBoxStyles: {
                height: 'max min(40x, 45vh)',
            }, onSelectionChange: onFilterAdd, onBlur: () => setMode(null), onKeyDown: (e) => {
                if (e.key === 'Escape') {
                    setMode(null);
                }
            }, children: shownMembers.map((member) => {
                const memberName = member.name.split('.')[1];
                const cubeName = member.name.split('.')[0];
                const cube = cubes.find((cube) => cube.name === cubeName);
                return (_jsx(Select.Item, { textValue: member.name, children: _jsx(MemberLabel, { name: member.name, memberName: memberName, memberTitle: member.shortTitle, cubeName: cubeName, cubeTitle: cube?.title, memberViewType: memberViewType, isCompact: isCompact, type: 'type' in member ? member.type : undefined, memberType: mode === 'dateRange' ? 'timeDimension' : mode }) }, member.name));
            }) })) }));
}
//# sourceMappingURL=AddFilterInput.js.map