import { getMemoOptions, makeStateUpdater, memo } from '../utils';
//
export const RowSelection = {
    getInitialState: (state) => {
        return {
            rowSelection: {},
            ...state,
        };
    },
    getDefaultOptions: (table) => {
        return {
            onRowSelectionChange: makeStateUpdater('rowSelection', table),
            enableRowSelection: true,
            enableMultiRowSelection: true,
            enableSubRowSelection: true,
            // enableGroupingRowSelection: false,
            // isAdditiveSelectEvent: (e: unknown) => !!e.metaKey,
            // isInclusiveSelectEvent: (e: unknown) => !!e.shiftKey,
        };
    },
    createTable: (table) => {
        table.setRowSelection = (updater) => { var _a, _b; return (_b = (_a = table.options).onRowSelectionChange) === null || _b === void 0 ? void 0 : _b.call(_a, updater); };
        table.resetRowSelection = (defaultState) => { var _a; return table.setRowSelection(defaultState ? {} : ((_a = table.initialState.rowSelection) !== null && _a !== void 0 ? _a : {})); };
        table.toggleAllRowsSelected = (value) => {
            table.setRowSelection((old) => {
                value = typeof value !== 'undefined' ? value : !table.getIsAllRowsSelected();
                const rowSelection = { ...old };
                const preGroupedFlatRows = table.getPreGroupedRowModel().flatRows;
                // We don't use `mutateRowIsSelected` here for performance reasons.
                // All of the rows are flat already, so it wouldn't be worth it
                if (value) {
                    preGroupedFlatRows.forEach((row) => {
                        if (!row.getCanSelect()) {
                            return;
                        }
                        rowSelection[row.id] = true;
                    });
                }
                else {
                    preGroupedFlatRows.forEach((row) => {
                        delete rowSelection[row.id];
                    });
                }
                return rowSelection;
            });
        };
        table.toggleAllPageRowsSelected = (value) => table.setRowSelection((old) => {
            const resolvedValue = typeof value !== 'undefined' ? value : !table.getIsAllPageRowsSelected();
            const rowSelection = { ...old };
            table.getRowModel().rows.forEach((row) => {
                mutateRowIsSelected(rowSelection, row.id, resolvedValue, true, table);
            });
            return rowSelection;
        });
        // addRowSelectionRange: rowId => {
        //   const {
        //     rows,
        //     rowsById,
        //     options: { selectGroupingRows, selectSubRows },
        //   } = table
        //   const findSelectedRow = (rows: Row[]) => {
        //     let found
        //     rows.find(d => {
        //       if (d.getIsSelected()) {
        //         found = d
        //         return true
        //       }
        //       const subFound = findSelectedRow(d.subRows || [])
        //       if (subFound) {
        //         found = subFound
        //         return true
        //       }
        //       return false
        //     })
        //     return found
        //   }
        //   const firstRow = findSelectedRow(rows) || rows[0]
        //   const lastRow = rowsById[rowId]
        //   let include = false
        //   const selectedRowIds = {}
        //   const addRow = (row: Row) => {
        //     mutateRowIsSelected(selectedRowIds, row.id, true, {
        //       rowsById,
        //       selectGroupingRows: selectGroupingRows!,
        //       selectSubRows: selectSubRows!,
        //     })
        //   }
        //   table.rows.forEach(row => {
        //     const isFirstRow = row.id === firstRow.id
        //     const isLastRow = row.id === lastRow.id
        //     if (isFirstRow || isLastRow) {
        //       if (!include) {
        //         include = true
        //       } else if (include) {
        //         addRow(row)
        //         include = false
        //       }
        //     }
        //     if (include) {
        //       addRow(row)
        //     }
        //   })
        //   table.setRowSelection(selectedRowIds)
        // },
        table.getPreSelectedRowModel = () => table.getCoreRowModel();
        table.getSelectedRowModel = memo(() => [table.getState().rowSelection, table.getCoreRowModel()], (rowSelection, rowModel) => {
            if (!Object.keys(rowSelection).length) {
                return {
                    rows: [],
                    flatRows: [],
                    rowsById: {},
                };
            }
            return selectRowsFn(table, rowModel);
        }, getMemoOptions(table.options, 'debugTable', 'getSelectedRowModel'));
        table.getFilteredSelectedRowModel = memo(() => [table.getState().rowSelection, table.getFilteredRowModel()], (rowSelection, rowModel) => {
            if (!Object.keys(rowSelection).length) {
                return {
                    rows: [],
                    flatRows: [],
                    rowsById: {},
                };
            }
            return selectRowsFn(table, rowModel);
        }, getMemoOptions(table.options, 'debugTable', 'getFilteredSelectedRowModel'));
        table.getGroupedSelectedRowModel = memo(() => [table.getState().rowSelection, table.getSortedRowModel()], (rowSelection, rowModel) => {
            if (!Object.keys(rowSelection).length) {
                return {
                    rows: [],
                    flatRows: [],
                    rowsById: {},
                };
            }
            return selectRowsFn(table, rowModel);
        }, getMemoOptions(table.options, 'debugTable', 'getGroupedSelectedRowModel'));
        ///
        // getGroupingRowCanSelect: rowId => {
        //   const row = table.getRow(rowId)
        //   if (!row) {
        //     throw new Error()
        //   }
        //   if (typeof table.options.enableGroupingRowSelection === 'function') {
        //     return table.options.enableGroupingRowSelection(row)
        //   }
        //   return table.options.enableGroupingRowSelection ?? false
        // },
        table.getIsAllRowsSelected = () => {
            const preGroupedFlatRows = table.getFilteredRowModel().flatRows;
            const { rowSelection } = table.getState();
            let isAllRowsSelected = Boolean(preGroupedFlatRows.length && Object.keys(rowSelection).length);
            if (isAllRowsSelected) {
                if (preGroupedFlatRows.some((row) => row.getCanSelect() && !rowSelection[row.id])) {
                    isAllRowsSelected = false;
                }
            }
            return isAllRowsSelected;
        };
        table.getIsAllPageRowsSelected = () => {
            const paginationFlatRows = table
                .getPaginationRowModel()
                .flatRows.filter((row) => row.getCanSelect());
            const { rowSelection } = table.getState();
            let isAllPageRowsSelected = !!paginationFlatRows.length;
            if (isAllPageRowsSelected && paginationFlatRows.some((row) => !rowSelection[row.id])) {
                isAllPageRowsSelected = false;
            }
            return isAllPageRowsSelected;
        };
        table.getIsSomeRowsSelected = () => {
            var _a;
            const totalSelected = Object.keys((_a = table.getState().rowSelection) !== null && _a !== void 0 ? _a : {}).length;
            return totalSelected > 0 && totalSelected < table.getFilteredRowModel().flatRows.length;
        };
        table.getIsSomePageRowsSelected = () => {
            const paginationFlatRows = table.getPaginationRowModel().flatRows;
            return table.getIsAllPageRowsSelected()
                ? false
                : paginationFlatRows
                    .filter((row) => row.getCanSelect())
                    .some((d) => d.getIsSelected() || d.getIsSomeSelected());
        };
        table.getToggleAllRowsSelectedHandler = () => {
            return (e) => {
                table.toggleAllRowsSelected(e.target.checked);
            };
        };
        table.getToggleAllPageRowsSelectedHandler = () => {
            return (e) => {
                table.toggleAllPageRowsSelected(e.target.checked);
            };
        };
    },
    createRow: (row, table) => {
        row.toggleSelected = (value, opts) => {
            const isSelected = row.getIsSelected();
            table.setRowSelection((old) => {
                var _a;
                value = typeof value !== 'undefined' ? value : !isSelected;
                if (row.getCanSelect() && isSelected === value) {
                    return old;
                }
                const selectedRowIds = { ...old };
                mutateRowIsSelected(selectedRowIds, row.id, value, (_a = opts === null || opts === void 0 ? void 0 : opts.selectChildren) !== null && _a !== void 0 ? _a : true, table);
                return selectedRowIds;
            });
        };
        row.getIsSelected = () => {
            const { rowSelection } = table.getState();
            return isRowSelected(row, rowSelection);
        };
        row.getIsSomeSelected = () => {
            const { rowSelection } = table.getState();
            return isSubRowSelected(row, rowSelection, table) === 'some';
        };
        row.getIsAllSubRowsSelected = () => {
            const { rowSelection } = table.getState();
            return isSubRowSelected(row, rowSelection, table) === 'all';
        };
        row.getCanSelect = () => {
            var _a;
            if (typeof table.options.enableRowSelection === 'function') {
                return table.options.enableRowSelection(row);
            }
            return (_a = table.options.enableRowSelection) !== null && _a !== void 0 ? _a : true;
        };
        row.getCanSelectSubRows = () => {
            var _a;
            if (typeof table.options.enableSubRowSelection === 'function') {
                return table.options.enableSubRowSelection(row);
            }
            return (_a = table.options.enableSubRowSelection) !== null && _a !== void 0 ? _a : true;
        };
        row.getCanMultiSelect = () => {
            var _a;
            if (typeof table.options.enableMultiRowSelection === 'function') {
                return table.options.enableMultiRowSelection(row);
            }
            return (_a = table.options.enableMultiRowSelection) !== null && _a !== void 0 ? _a : true;
        };
        row.getToggleSelectedHandler = () => {
            const canSelect = row.getCanSelect();
            return (e) => {
                var _a;
                if (!canSelect)
                    return;
                row.toggleSelected((_a = e.target) === null || _a === void 0 ? void 0 : _a.checked);
            };
        };
    },
};
const mutateRowIsSelected = (selectedRowIds, id, value, includeChildren, table) => {
    var _a;
    const row = table.getRow(id, true);
    // const isGrouped = row.getIsGrouped()
    // if ( // TODO: enforce grouping row selection rules
    //   !isGrouped ||
    //   (isGrouped && table.options.enableGroupingRowSelection)
    // ) {
    if (value) {
        if (!row.getCanMultiSelect()) {
            Object.keys(selectedRowIds).forEach((key) => delete selectedRowIds[key]);
        }
        if (row.getCanSelect()) {
            selectedRowIds[id] = true;
        }
    }
    else {
        delete selectedRowIds[id];
    }
    // }
    if (includeChildren && ((_a = row.subRows) === null || _a === void 0 ? void 0 : _a.length) && row.getCanSelectSubRows()) {
        row.subRows.forEach((subRow) => mutateRowIsSelected(selectedRowIds, subRow.id, value, includeChildren, table));
    }
};
export function selectRowsFn(table, rowModel) {
    const { rowSelection } = table.getState();
    const newSelectedFlatRows = [];
    const newSelectedRowsById = {};
    // Filters top level and nested rows
    const recurseRows = (rows, depth = 0) => {
        return rows
            .map((row) => {
            var _a;
            const isSelected = isRowSelected(row, rowSelection);
            if (isSelected) {
                newSelectedFlatRows.push(row);
                newSelectedRowsById[row.id] = row;
            }
            if ((_a = row.subRows) === null || _a === void 0 ? void 0 : _a.length) {
                // eslint-disable-next-line no-param-reassign -- 保持原逻辑：先合并 subRows 再根据 isSelected 返回
                row = {
                    ...row,
                    subRows: recurseRows(row.subRows, depth + 1),
                };
            }
            if (isSelected)
                return row;
            return undefined;
        })
            .filter(Boolean);
    };
    return {
        rows: recurseRows(rowModel.rows),
        flatRows: newSelectedFlatRows,
        rowsById: newSelectedRowsById,
    };
}
export function isRowSelected(row, selection) {
    var _a;
    return (_a = selection[row.id]) !== null && _a !== void 0 ? _a : false;
}
export function isSubRowSelected(row, selection, table) {
    var _a;
    if (!((_a = row.subRows) === null || _a === void 0 ? void 0 : _a.length))
        return false;
    let allChildrenSelected = true;
    let someSelected = false;
    row.subRows.forEach((subRow) => {
        // Bail out early if we know both of these
        if (someSelected && !allChildrenSelected) {
            return;
        }
        if (subRow.getCanSelect()) {
            if (isRowSelected(subRow, selection)) {
                someSelected = true;
            }
            else {
                allChildrenSelected = false;
            }
        }
        // Check row selection of nested subrows
        if (subRow.subRows && subRow.subRows.length) {
            const subRowChildrenSelected = isSubRowSelected(subRow, selection, table);
            if (subRowChildrenSelected === 'all') {
                someSelected = true;
            }
            else if (subRowChildrenSelected === 'some') {
                someSelected = true;
                allChildrenSelected = false;
            }
            else {
                allChildrenSelected = false;
            }
        }
    });
    if (allChildrenSelected)
        return 'all';
    if (someSelected)
        return 'some';
    return false;
}
