import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { DragOutlined } from '@ant-design/icons';
import { Button, Checkbox, ComboBox, Content, Dialog, DialogTrigger, DownIcon, Flow, Grid, Link, NumberInput, Radio, Select, Space, Tag, tasty, Text, Title, } from '@cube-dev/ui-kit';
import { forwardRef, useEffect, useMemo, useState } from 'react';
import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';
import { useStoredTimezones, useEvent } from './hooks';
import { MemberLabel } from './components/MemberLabel';
import { InfoIconButton } from './components/InfoIconButton';
import { useQueryBuilderContext } from './context';
import { ORDER_LABEL_BY_TYPE } from './utils/labels';
import { formatNumber } from './utils/formatters';
import { TIMEZONES } from './utils/timezones';
const DEFAULT_LIMIT = 0; // no limit
const ALL_TIMEZONES = [
    {
        tzCode: '',
        label: 'UTC (default)',
        name: 'Coordinated Universal Time',
        utc: '+00:00',
    },
    ...TIMEZONES,
];
const AVAILABLE_TIMEZONES = ALL_TIMEZONES.map((tz) => tz.tzCode);
const LIMIT_OPTIONS = [
    { key: 100, label: '100' },
    { key: 1000, label: '1,000' },
    { key: 5000, label: '5,000' },
    { key: 50000, label: '50,000' },
    { key: 0, label: 'Default limit' },
];
const LIMIT_OPTION_VALUES = LIMIT_OPTIONS.map((option) => option.key);
function timezoneByName(name) {
    return {
        tzCode: name,
        label: name,
        name: name,
        utc: '',
    };
}
const SortButton = tasty(Radio.Button, {
    inputStyles: {
        display: 'grid',
        placeContent: 'center',
        preset: 't4m',
        height: '3x',
        padding: '.5x .75x',
        fill: {
            '': '#white',
            // hovered: '#clear',
            checked: '#active',
            disabled: '#dark.04',
        },
        color: {
            '': '#dark-02',
            hovered: '#active',
            checked: '#white',
        },
        border: {
            '': '#hover',
            checked: '#active',
        },
        backgroundClip: 'padding-box',
    },
});
const OrderListContainer = tasty(Flow, {
    qa: 'OrderList',
    styles: {
        flow: 'column',
        gap: '1ow',
    },
});
const OrderListItemStyled = tasty(Grid, {
    qa: 'OrderItem',
    styles: {
        gridTemplateColumns: 'auto 1fr auto',
        flow: 'row',
        gap: '1x',
        fill: {
            '': '#fill',
            ':hover': '#hover',
        },
        radius: true,
        padding: '1ow 1ow 1ow .75x',
        placeContent: 'start',
        placeItems: 'center start',
        transition: 'theme',
        '--active-color': {
            '': '#dark',
            '[data-member="measure"]': '#measure-text',
            '[data-member="dimension"]': '#dimension-text',
            '[data-member="timeDimension"]': '#time-dimension-text',
            '[data-member="segment"]': '#segment-text',
        },
        '--fill-color': {
            '': '#dark-05',
            '[data-member="measure"]': '#measure-hover',
            '[data-member="dimension"]': '#dimension-hover',
            '[data-member="timeDimension"]': '#time-dimension-hover',
            '[data-member="segment"]': '#segment-hover',
        },
        '--hover-color': {
            '': '#dark',
            '[data-member="measure"]': '#measure-active',
            '[data-member="dimension"]': '#dimension-active',
            '[data-member="timeDimension"]': '#time-dimension-active',
            '[data-member="segment"]': '#segment-active',
        },
    },
});
export function sortFields(fields, sortedFields) {
    return [...fields].sort((a, b) => {
        if (sortedFields.includes(a) && sortedFields.includes(b)) {
            return sortedFields.indexOf(a) - sortedFields.indexOf(b);
        }
        if (sortedFields.includes(a)) {
            return -1;
        }
        if (sortedFields.includes(b)) {
            return 1;
        }
        return 0;
    });
}
export const OrderListItem = forwardRef(function OrderListItem(props, ref) {
    const { name, memberType, cubeMemberKind, defaultSorting = 'none', onSortChange, ...otherProps } = props;
    const label = props.label ?? name;
    return (_jsxs(OrderListItemStyled, { ref: ref, "data-member": memberType, ...otherProps, children: [_jsx(DragOutlined, { style: { fontSize: 16 } }), _jsx(MemberLabel, { name: label, memberType: memberType }), _jsxs(Radio.ButtonGroup, { "aria-label": "Sorting", defaultValue: defaultSorting, orientation: "horizontal", onChange: (val) => onSortChange(name, val), children: [_jsx(SortButton, { "data-member": memberType, "aria-label": "Ascending", value: "asc", children: ORDER_LABEL_BY_TYPE[cubeMemberKind ?? 'string'][0] }), _jsx(SortButton, { "data-member": memberType, "aria-label": "Descending", value: "desc", children: ORDER_LABEL_BY_TYPE[cubeMemberKind ?? 'string'][1] }), _jsx(SortButton, { "data-member": memberType, "aria-label": "No sorting", value: "none", children: "None" })] })] }, name));
});
export function QueryBuilderExtras() {
    const { query, members, updateQuery, order } = useQueryBuilderContext();
    const [showOrder, setShowOrder] = useState(true);
    const fields = [...(query?.dimensions ?? []), ...(query?.measures ?? [])];
    const storedTimezones = useStoredTimezones(query.timezone);
    const timeDimensions = query?.timeDimensions?.filter((time) => time.granularity).map((time) => time.dimension) ?? [];
    timeDimensions.forEach((name) => {
        if (name && !fields.includes(name)) {
            fields.push(name);
        }
    });
    const sortedFields = order.getOrder();
    const [allFields, setAllFields] = useState(sortFields(fields, sortedFields));
    fields.forEach((name) => {
        if (!allFields.includes(name)) {
            allFields.push(name);
        }
    });
    const copyFields = [...allFields];
    allFields.splice(0);
    allFields.push(...copyFields.filter((name) => fields.includes(name)));
    useEffect(() => {
        const filtered = allFields.filter((name) => sortedFields.includes(name));
        let newAllFields = allFields;
        if (filtered.join(',') !== sortedFields.join(',')) {
            newAllFields = sortFields(allFields, sortedFields);
            setAllFields(newAllFields);
        }
        // remove all deleted fields from sorted
        sortedFields.forEach((name) => {
            if (!newAllFields.includes(name)) {
                order.remove(name);
            }
        });
        setShowOrder(false);
    }, [allFields.concat(sortedFields).join(',')]);
    useEffect(() => {
        if (!showOrder) {
            setShowOrder(true);
        }
    }, [showOrder]);
    function getMemberType(name) {
        if (timeDimensions.includes(name)) {
            return 'timeDimension';
        }
        if (query?.dimensions?.includes(name)) {
            return 'dimension';
        }
        if (query?.measures?.includes(name)) {
            return 'measure';
        }
        return undefined;
    }
    function getMember(name) {
        return members?.measures[name] || members?.dimensions[name];
    }
    function onSortChange(name, sorting) {
        if (sorting === 'none') {
            order.remove(name);
        }
        else {
            order.set(name, sorting);
            order.setOrder(allFields);
        }
    }
    const onDrag = useEvent(({ source, destination }) => {
        if (!destination) {
            return;
        }
        const newOrder = [...allFields];
        newOrder.splice(source.index, 1);
        newOrder.splice(destination.index, 0, allFields[source.index]);
        order.setOrder(newOrder);
        setAllFields(newOrder);
    });
    const optionsPopover = useMemo(() => {
        // ungrouped
        const isSelected = query.ungrouped ||
            query.total ||
            query.timezone ||
            query.offset ||
            (query.limit && query.limit !== DEFAULT_LIMIT);
        const selectedCount = (query.ungrouped ? 1 : 0) +
            (query.total ? 1 : 0) +
            (query.timezone ? 1 : 0) +
            (query.limit && query.limit !== DEFAULT_LIMIT ? 1 : 0) +
            (query.offset ? 1 : 0);
        // timezone
        const timezone = query?.timezone || '';
        const optionsWithStored = [...ALL_TIMEZONES];
        [...storedTimezones].reverse().forEach((name) => {
            if (!AVAILABLE_TIMEZONES.includes(name)) {
                optionsWithStored.unshift(timezoneByName(name));
            }
            else {
                const option = optionsWithStored.find((tz) => tz.tzCode === name);
                if (option) {
                    optionsWithStored.splice(optionsWithStored.indexOf(option), 1);
                    optionsWithStored.unshift(option);
                }
            }
        });
        const options = optionsWithStored.map((tz) => tz.tzCode).includes(timezone)
            ? optionsWithStored
            : [timezoneByName(timezone), ...optionsWithStored];
        return (_jsxs(DialogTrigger, { type: "popover", placement: "bottom end", children: [_jsxs(Button, { qa: "QueryOptions", "aria-label": "Query options", type: isSelected ? 'primary' : 'secondary', size: "small", rightIcon: _jsx(DownIcon, {}), children: ["Options", selectedCount ? (_jsx(Tag, { color: "#purple-text", fill: "#white", border: false, children: selectedCount })) : null] }), (close) => (_jsx(Dialog, { width: "36x", children: _jsxs(Content, { padding: "1x 1.5x", gap: "1.5x", children: [_jsxs(Flow, { gap: "1x", children: [_jsxs(Space, { gap: ".25x", children: [_jsx(Title, { level: 4, preset: "h6", children: "Query" }), _jsx(InfoIconButton, { tooltip: "Click to learn more about the query format", tooltipSuffix: "", to: "!https://cube.dev/reference/core-data-apis/rest-api/query-format" })] }), _jsx(Checkbox, { "aria-label": "Ungrouped", isSelected: query.ungrouped ?? false, onChange: (ungrouped) => {
                                            updateQuery({ ungrouped: ungrouped || undefined });
                                            close();
                                        }, children: "Ungrouped" }), _jsx(Checkbox, { "aria-label": "Show total number of rows", isSelected: query.total ?? false, onChange: (total) => {
                                            updateQuery({ total: total || undefined });
                                            close();
                                        }, children: "Show total number of rows" })] }), _jsx(ComboBox, { "aria-label": "Timezone", label: "Time zone", size: "small", listBoxStyles: { height: '41x' }, extra: timezone ? (_jsx(Link, { onPress: () => {
                                        updateQuery({ timezone: undefined });
                                        close();
                                    }, children: "Reset" })) : null, selectedKey: timezone, onSelectionChange: (val) => {
                                    if (!val) {
                                        return;
                                    }
                                    const timezone = val;
                                    updateQuery(() => ({
                                        timezone: timezone === '' ? undefined : timezone,
                                    }));
                                    close();
                                }, children: options.map((tz) => {
                                    const name = tz.tzCode;
                                    const zone = tz.utc;
                                    return (_jsx(Select.Item, { textValue: tz.label, children: _jsxs(Space, { placeContent: "space-between", preset: "t3m", children: [_jsx(Text, { nowrap: true, ellipsis: true, block: true, styles: { width: 'max 40x' }, children: name || 'UTC (Default)' }), zone ? (_jsxs(Text, { nowrap: true, font: "monospace", preset: "c2", children: ["GMT", zone] })) : undefined] }) }, tz.tzCode));
                                }) }), _jsx(QueryBuilderLimitSelect, {}), _jsx(NumberInput, { label: "Offset", size: "small", wrapperStyles: { width: 'auto' }, extra: query?.offset ? (_jsx(Link, { onPress: () => {
                                        updateQuery({ offset: undefined });
                                        close();
                                    }, children: "Reset" })) : null, minValue: 0, value: query?.offset ?? 0, onChange: (val) => {
                                    updateQuery({ offset: val });
                                }, onKeyDown: (e) => {
                                    // close on Enter
                                    if (e.key === 'Enter') {
                                        close();
                                        e.preventDefault();
                                    }
                                } })] }) }))] }));
    }, [
        query.ungrouped,
        query.timezone,
        query.offset,
        query.total,
        storedTimezones.join('::'),
        query.limit,
    ]);
    const orderSelector = useMemo(() => {
        if (!allFields.length) {
            return;
        }
        return (_jsxs(DialogTrigger, { type: "popover", placement: "bottom end", children: [_jsx(Button, { qa: "OrderButton", type: sortedFields.length ? 'primary' : 'secondary', size: "small", rightIcon: _jsx(DownIcon, {}), children: sortedFields.length ? (_jsxs(_Fragment, { children: ["Order", _jsx(Tag, { color: "#purple-text", fill: "#white", border: false, children: sortedFields.length })] })) : ('Order') }), _jsx(Dialog, { width: "max 80x", children: _jsx(Content, { padding: "(1.5x - 1ow)", style: { minHeight: `${30 * allFields.length + 18}px` }, children: _jsx(DragDropContext, { onDragEnd: onDrag, children: _jsx(Droppable, { droppableId: "queryOrder", children: (provided) => (_jsxs(OrderListContainer, { ref: provided.innerRef, ...provided.droppableProps, children: [allFields.map((name, index) => {
                                            const memberType = getMemberType(name);
                                            return (_jsx(Draggable, { draggableId: name, index: index, children: ({ draggableProps, dragHandleProps, innerRef }) => (_jsx(OrderListItem, { ref: innerRef, name: name, "data-member": memberType, memberType: memberType, defaultSorting: order.get(name) ?? 'none', cubeMemberKind: getMember(name)?.type, onSortChange: onSortChange, ...draggableProps, ...dragHandleProps }, name)) }, name));
                                        }), provided.placeholder] })) }) }) }) })] }));
    }, [JSON.stringify(order.map), JSON.stringify(allFields), showOrder]);
    return (_jsxs(Space, { gap: "1x", children: [orderSelector, optionsPopover] }));
}
export function QueryBuilderLimitSelect() {
    const { query, updateQuery } = useQueryBuilderContext();
    const limit = query.limit ?? DEFAULT_LIMIT;
    const limitOptions = LIMIT_OPTION_VALUES.includes(limit)
        ? LIMIT_OPTIONS
        : [{ key: limit, label: formatNumber(limit) }, ...LIMIT_OPTIONS].sort((a, b) => a.key - b.key);
    return (_jsx(Select, { label: "Limit", size: "small", extra: limit !== DEFAULT_LIMIT ? (_jsx(Link, { onPress: () => {
                updateQuery({ limit: undefined });
                close();
            }, children: "Reset" })) : null, labelSuffix: _jsx(InfoIconButton, { tooltip: "Click to learn more about the row limit", tooltipSuffix: "", to: "!https://cube.dev/reference/core-data-apis/rest-api/query-format#row-limit" }), selectedKey: query.limit == null ? '0' : String(query.limit), onSelectionChange: (val) => {
            updateQuery(() => ({ limit: val === '0' ? undefined : Number(val) }));
            close();
        }, children: limitOptions.map((option) => (_jsx(Select.Item, { textValue: option.label, children: option.label }, option.key))) }));
}
//# sourceMappingURL=QueryBuilderExtras.js.map