import * as React from 'react';
import useSelection from './useSelection';
import { CheckBox } from '../../../components/CheckBox';
import Radio from '../../../components/Radio';
import Dropdown from '../../../components/Dropdown';
import Input from '../../../components/Input';
import { useRef, useState } from 'react';
import StringExtensions from '../../../Utilities/Extensions/StringExtensions';
import { DataSource, InfiniteTable } from '../../../components/InfiniteTable';
import { Box, Flex } from 'rebass';
import throttle from 'lodash/throttle';
const dataTypes = [
    {
        value: 'text',
        label: 'Text (string)',
    },
    { value: 'number', label: 'Number' },
    {
        value: 'date',
        label: 'Date',
    },
    {
        value: 'boolean',
        label: 'Boolean',
    },
];
const inputStyle = {
    width: '100%',
    minWidth: 80,
    textAlign: 'start',
};
const useForceRender = () => {
    const [, setNow] = useState(Date.now());
    return () => {
        setNow(Date.now());
    };
};
const ThrottledInput = React.memo((props) => {
    const [stateValue, setStateValue] = useState(props.value);
    const throttleOnChange = React.useRef(throttle(props.onChange, 600, { leading: false }));
    const handleChange = React.useCallback((event) => {
        const newValue = event.target.value;
        setStateValue(newValue);
        throttleOnChange.current(newValue);
    }, []);
    React.useEffect(() => {
        setStateValue(props.value);
    }, [props.value]);
    return React.createElement(Input, { style: props.style, value: stateValue, onChange: handleChange });
});
const tableDOMProps = {
    style: {
        height: '100%',
        minWidth: '10rem',
        minHeight: 600,
    },
};
const ColumnsList = ({ columns: cols, handle, onValidityChange, onChange, onSelectionChange, selectedColumns, theme, }) => {
    const rerender = useForceRender();
    const columnsRef = useRef(cols);
    const silentSetColumns = (columns) => {
        columnsRef.current = columns;
        onChange?.(columns);
    };
    const setColumns = (columns) => {
        silentSetColumns(columns);
        rerender();
    };
    const getColumns = () => columnsRef.current;
    const columns = columnsRef.current;
    const onColumnChange = (col, value, property) => {
        col = { ...col, [property]: value };
        const cols = getColumns().map((c) => {
            if (c.field === col.field) {
                return col;
            }
            return c;
        });
        setColumns(cols);
    };
    const onColumnBatchChange = (value, property) => {
        const cols = getColumns().map((c) => ({ ...c, [property]: value }));
        setColumns(cols);
    };
    const setColumnCaption = (caption, field) => {
        const cols = getColumns().map((c) => {
            if (c.field === field) {
                const newCol = { ...c, caption };
                return newCol;
            }
            return c;
        });
        setColumns(cols);
    };
    const onColumnTypeChange = (col, type) => {
        const cols = getColumns().map((c) => {
            if (c.field === col.field) {
                return { ...c, type };
            }
            return c;
        });
        setColumns(cols);
    };
    const [primaryKeyField, setPrimaryKeyField] = React.useState(columns[0].field);
    const { selected: includedColumnsMap, isSelected: isIncludedColumn, isAllSelected: isAllIncludedColumns, isNoneSelected: isNoneIncludedColumns, selectColumn: includeColumn, deselectColumn: excludeColumn, selectAll: includeAllColumns, deselectAll: excludeAllColumns, } = useSelection(columns, selectedColumns ?? true, null, { onChange: onSelectionChange });
    handle.current = {
        getColumns: () => getColumns().filter((col) => isIncludedColumn(col.field)),
        getPrimaryKey: () => primaryKeyField,
    };
    const { isSelected: isSortableColumn, isAllSelected: isAllSortableColumns, isNoneSelected: isNoneSortableColumns, selectColumn: setSortableColumn, deselectColumn: setUnsortableColumn, selectAll: setAllSortable, deselectAll: setAllUnsortable, } = useSelection(columns, true, 'sortable', {
        onBatchChange: (flag) => {
            onColumnBatchChange(flag, 'sortable');
        },
        onChange: (col, flag) => {
            onColumnChange(col, flag, 'sortable');
        },
    });
    const { isSelected: isGroupableColumn, isAllSelected: isAllGroupableColumns, isNoneSelected: isNoneGroupableColumns, selectColumn: setGroupableColumn, deselectColumn: setUngroupableColumn, selectAll: setAllGroupable, deselectAll: setAllUngroupable, } = useSelection(columns, true, 'enableRowGroup', {
        onBatchChange: (flag) => {
            onColumnBatchChange(flag, 'enableRowGroup');
        },
        onChange: (col, flag) => {
            onColumnChange(col, flag, 'enableRowGroup');
        },
    });
    const { isSelected: isResizableColumn, isAllSelected: isAllResizableColumns, isNoneSelected: isNoneResizableColumns, selectColumn: setResizableColumn, deselectColumn: setUnresizableColumn, selectAll: setAllResizable, deselectAll: setAllUnresizable, } = useSelection(columns, true, 'resizable', {
        onBatchChange: (flag) => {
            onColumnBatchChange(flag, 'resizable');
        },
        onChange: (col, flag) => {
            onColumnChange(col, flag, 'resizable');
        },
    });
    const { isSelected: isEditableColumn, isAllSelected: isAllEditableColumns, isNoneSelected: isNoneEditableColumns, selectColumn: setEditableColumn, deselectColumn: setUneditableColumn, selectAll: setAllEditable, deselectAll: setAllUneditable, } = useSelection(columns, true, 'editable', {
        onBatchChange: (flag) => {
            onColumnBatchChange(flag, 'editable');
        },
        onChange: (col, flag) => {
            onColumnChange(col, flag, 'editable');
        },
    });
    const { isSelected: isFilterableColumn, isAllSelected: isAllFilterableColumns, isNoneSelected: isNoneFilterableColumns, selectColumn: setFilterableColumn, deselectColumn: setUnFilterableColumn, selectAll: setAllFilterable, deselectAll: setAllUnfilterable, } = useSelection(columns, true, 'filter', {
        onBatchChange: (flag) => {
            onColumnBatchChange(flag, 'filter');
        },
        onChange: (col, flag) => {
            onColumnChange(col, flag, 'filter');
        },
    });
    const allIncluded = isAllIncludedColumns();
    const allExcluded = isNoneIncludedColumns();
    React.useEffect(() => {
        onValidityChange(isIncludedColumn(primaryKeyField));
    }, [includedColumnsMap, primaryKeyField]);
    const data = columns;
    const CellWrapper = (props) => {
        return (React.createElement(Flex, { ...props, style: {
                ...props.style,
                position: 'absolute',
                textAlign: 'center',
                top: 0,
                left: 0,
                height: '100%',
                width: '100%',
                whiteSpace: 'normal',
            }, justifyContent: "center", alignItems: "center" }, props.children));
    };
    const HeaderCellWrapper = (props) => (React.createElement(CellWrapper, { ...props, fontSize: 3, style: { fontWeight: 600 } }));
    const HeaderWithCheckbox = (props) => {
        const { label, onChange, checked, ...flexProps } = props;
        return (React.createElement(HeaderCellWrapper, { ...flexProps, flexDirection: "column" },
            React.createElement(Box, null, label),
            React.createElement(Box, { style: { textAlign: 'center' } },
                React.createElement(CheckBox, { checked: checked, onChange: onChange }))));
    };
    const columnsMap = {
        pk: {
            header: () => React.createElement(HeaderCellWrapper, null, "Primary Key"),
            maxWidth: 80,
            defaultSortable: false,
            renderMenuIcon: false,
            render: (params) => {
                const { data } = params;
                const column = data;
                const isPrimaryKey = column?.field === primaryKeyField;
                return (React.createElement(Radio, { checked: isPrimaryKey, onChange: (checked) => {
                        if (checked && isIncludedColumn(column.field)) {
                            setPrimaryKeyField(column.field);
                        }
                    } }));
            },
        },
        included: {
            maxWidth: 80,
            resizable: true,
            renderMenuIcon: false,
            header: () => (React.createElement(HeaderWithCheckbox, { label: "Included", checked: allIncluded ? true : allExcluded ? false : null, onChange: (allIncluded) => {
                    if (allIncluded) {
                        includeAllColumns();
                    }
                    else {
                        excludeAllColumns();
                    }
                } })),
            render: (params) => {
                const column = params.data;
                return (React.createElement(CellWrapper, null,
                    React.createElement(CheckBox, { checked: isIncludedColumn(column.field), onChange: (included) => {
                            if (included) {
                                includeColumn(column.field);
                            }
                            else {
                                excludeColumn(column.field);
                            }
                        } })));
            },
        },
        field: {
            header: React.createElement(HeaderCellWrapper, null, "Field"),
            field: 'field',
            minWidth: 150,
            renderMenuIcon: false,
            render: (params) => {
                const column = params.data;
                const humanized = StringExtensions.Humanize(column.field);
                return (React.createElement(Box, { p: 2 },
                    React.createElement(ThrottledInput, { key: column.field, style: inputStyle, value: column.caption != undefined ? column.caption : humanized, placeholder: humanized, onChange: (value) => {
                            setColumnCaption(value, column.field);
                        } })));
            },
        },
        type: {
            header: React.createElement(HeaderCellWrapper, null, "Type"),
            maxWidth: 140,
            renderMenuIcon: false,
            render: (params) => {
                const column = params.data;
                return (React.createElement(CellWrapper, { paddingLeft: 1, paddingRight: 1 },
                    React.createElement(Dropdown, { style: inputStyle, showClearButton: false, options: dataTypes, value: column?.type ?? '', onChange: onColumnTypeChange.bind(null, column) })));
            },
        },
        sortable: {
            renderMenuIcon: false,
            header: (React.createElement(HeaderWithCheckbox, { label: "Sortable", checked: isAllSortableColumns() ? true : isNoneSortableColumns() ? false : null, onChange: (allSortable) => {
                    if (allSortable) {
                        setAllSortable();
                    }
                    else {
                        setAllUnsortable();
                    }
                } })),
            render: (params) => {
                const column = params.data;
                return (React.createElement(CheckBox, { checked: isSortableColumn(column.field), onChange: (sortable) => {
                        sortable ? setSortableColumn(column.field) : setUnsortableColumn(column.field);
                    } }));
            },
        },
        editable: {
            renderMenuIcon: false,
            header: (React.createElement(HeaderWithCheckbox, { label: "Editable", checked: isAllEditableColumns() ? true : isNoneEditableColumns() ? false : null, onChange: (allEditable) => {
                    if (allEditable) {
                        setAllEditable();
                    }
                    else {
                        setAllUneditable();
                    }
                } })),
            render: (params) => {
                const col = params.data;
                return (React.createElement(CellWrapper, null,
                    React.createElement(CheckBox, { checked: isEditableColumn(col.field), onChange: (editable) => {
                            editable ? setEditableColumn(col.field) : setUneditableColumn(col.field);
                        } })));
            },
        },
        resizable: {
            renderMenuIcon: false,
            header: (React.createElement(HeaderWithCheckbox, { label: "Resizable", checked: isAllResizableColumns() ? true : isNoneResizableColumns() ? false : null, onChange: (allResizable) => {
                    if (allResizable) {
                        setAllResizable();
                    }
                    else {
                        setAllUnresizable();
                    }
                } })),
            render: (params) => {
                const col = params.data;
                return (React.createElement(CellWrapper, null,
                    React.createElement(CheckBox, { checked: isResizableColumn(col.field), onChange: (resizable) => {
                            resizable ? setResizableColumn(col.field) : setUnresizableColumn(col.field);
                        } })));
            },
        },
        groupable: {
            renderMenuIcon: false,
            header: (React.createElement(HeaderWithCheckbox, { label: "Groupable", checked: isAllGroupableColumns() ? true : isNoneGroupableColumns() ? false : null, onChange: (allGroupable) => {
                    if (allGroupable) {
                        setAllGroupable();
                    }
                    else {
                        setAllUngroupable();
                    }
                } })),
            render: (params) => {
                const col = params.data;
                return (React.createElement(CellWrapper, null,
                    React.createElement(CheckBox, { checked: isGroupableColumn(col.field), onChange: (groupable) => {
                            groupable ? setGroupableColumn(col.field) : setUngroupableColumn(col.field);
                        } })));
            },
        },
        filterable: {
            renderMenuIcon: false,
            header: (React.createElement(HeaderWithCheckbox, { label: "Filterable", checked: isAllFilterableColumns() ? true : isNoneFilterableColumns() ? false : null, onChange: (allFilterable) => {
                    if (allFilterable) {
                        setAllFilterable();
                    }
                    else {
                        setAllUnfilterable();
                    }
                } })),
            render: (params) => {
                const col = params.data;
                return (React.createElement(CellWrapper, null,
                    React.createElement(CheckBox, { checked: isFilterableColumn(col.field), onChange: (filterable) => {
                            filterable ? setFilterableColumn(col.field) : setUnFilterableColumn(col.field);
                        } })));
            },
        },
    };
    return (React.createElement(Box, { p: 2, style: { height: '100%' }, className: theme },
        React.createElement(DataSource, { data: data, primaryKey: "colId" },
            React.createElement(InfiniteTable, { columnTypes: {
                    default: {
                        defaultFlex: 1,
                        align: 'center',
                        defaultSortable: false,
                    },
                }, headerOptions: {
                    alwaysReserveSpaceForSortIcon: false,
                }, domProps: tableDOMProps, columns: columnsMap }))));
};
function areEqual() {
    /**
     * Make the ColumnList not render on subsequent prop changes
     * in order to boost performance
     */
    return true;
}
export default React.memo(ColumnsList, areEqual);
