import { getInternalProps, findCheckboxColumnIndex, setCellCheckboxStateByAttribute } from "./utils";

export function bindMasterDetailCheckboxChange(table, eventManager) {
    const checkboxChangeHandler = args => {
        var _a;
        const {col: col, row: row, checked: checked, field: field} = args;
        if (table.isHeader(col, row)) {
            const internalProps = getInternalProps(table);
            return void eventManager.getExpandedRows().forEach((expandedRow => {
                var _a;
                const bodyRowIndex = expandedRow - table.columnHeaderLevelCount, subTableInstance = null === (_a = internalProps.subTableInstances) || void 0 === _a ? void 0 : _a.get(bodyRowIndex);
                if (subTableInstance && field) {
                    updateAllSubTableCheckboxes(subTableInstance, "string" == typeof field ? field : String(field), checked);
                }
            }));
        }
        const rowIndex = row;
        if (!eventManager.isRowExpanded(rowIndex)) return;
        const bodyRowIndex = row - table.columnHeaderLevelCount, subTableInstance = null === (_a = getInternalProps(table).subTableInstances) || void 0 === _a ? void 0 : _a.get(bodyRowIndex);
        if (subTableInstance && field) {
            updateAllSubTableCheckboxes(subTableInstance, "string" == typeof field ? field : String(field), checked);
        }
    }, originalUpdateHeaderCheckedState = table.stateManager.updateHeaderCheckedState;
    table.stateManager.updateHeaderCheckedState = function(field, col, row) {
        const stateManager = this;
        let result, allChecked = !0, allUnChecked = !0, hasChecked = !1, hasIndeterminate = !1;
        return stateManager.checkedState.forEach(((check_state, index) => {
            var _a;
            index = index.includes(",") ? index.split(",").map((item => Number(item))) : Number(index);
            const tableIndex = stateManager.table.getTableIndexByRecordIndex(index), mergeCell = stateManager.table.transpose ? stateManager.table.getCustomMerge(tableIndex, row) : stateManager.table.getCustomMerge(col, tableIndex), data = null === (_a = stateManager.table.dataSource) || void 0 === _a ? void 0 : _a.get(index);
            if (mergeCell || !stateManager.table.internalProps.enableCheckboxCascade && (null == data ? void 0 : data.vtableMerge)) return;
            const checkValue = null == check_state ? void 0 : check_state[field];
            "indeterminate" === checkValue ? (hasIndeterminate = !0, hasChecked = !0, allChecked = !1, 
            allUnChecked = !1) : !0 !== checkValue ? allChecked = !1 : (allUnChecked = !1, hasChecked = !0);
        })), result = hasIndeterminate ? "indeterminate" : !!allChecked || !allUnChecked && (!!hasChecked && "indeterminate"), 
        stateManager.headerCheckedState[field] = result, result;
    }, table.on("checkbox_state_change", checkboxChangeHandler);
    const subTableCleanup = bindSubTableCheckboxEvents(table);
    return () => {
        table.off("checkbox_state_change", checkboxChangeHandler), table.stateManager.updateHeaderCheckedState = originalUpdateHeaderCheckedState, 
        subTableCleanup();
    };
}

function bindSubTableCheckboxEvents(table) {
    const internalProps = getInternalProps(table), originalSet = internalProps.subTableInstances.set;
    return originalSet && internalProps.subTableInstances ? (internalProps.subTableInstances.set = function(key, subTable) {
        const result = originalSet.call(this, key, subTable), checkboxHandler = args => {
            const {field: field} = args;
            updateMainTableRowCheckboxFromSubTable(table, subTable, key, field);
        };
        subTable.on("checkbox_state_change", checkboxHandler);
        return subTable.__checkboxHandler = checkboxHandler, result;
    }, () => {
        internalProps.subTableInstances && originalSet && (internalProps.subTableInstances.set = originalSet);
    }) : () => {};
}

function updateMainTableRowCheckboxFromSubTable(mainTable, subTable, subTableKey, field) {
    const mainTableRow = subTableKey + mainTable.columnHeaderLevelCount;
    let subTableState = !1;
    const headerState = subTable.stateManager.headerCheckedState[field];
    void 0 !== headerState && (subTableState = headerState);
    const mainTableCheckboxCol = findCheckboxColumnIndex(mainTable, field);
    if (-1 !== mainTableCheckboxCol && mainTable.stateManager) {
        mainTable.stateManager.setCheckedState(mainTableCheckboxCol, mainTableRow, field, subTableState);
        if ("checkbox" === mainTable.getCellType(mainTableCheckboxCol, mainTableRow) && setCellCheckboxStateByAttribute(mainTableCheckboxCol, mainTableRow, subTableState, mainTable), 
        mainTable.internalProps.enableCheckboxCascade) {
            const oldHeaderCheckedState = mainTable.stateManager.headerCheckedState[field], newHeaderCheckedState = mainTable.stateManager.updateHeaderCheckedState(field, mainTableCheckboxCol, 0);
            if (oldHeaderCheckedState !== newHeaderCheckedState) {
                const headerRow = 0;
                mainTable.isHeader(mainTableCheckboxCol, headerRow) && mainTable.scenegraph.updateHeaderCheckboxCellState(mainTableCheckboxCol, headerRow, newHeaderCheckedState);
            }
        }
    }
}

function updateAllSubTableCheckboxes(subTable, field, checked) {
    if (!subTable.stateManager) return;
    subTable.stateManager.headerCheckedState[field] = checked;
    (subTable.records || []).forEach(((record, recordIndex) => {
        const indexKey = recordIndex.toString();
        record[field] = checked;
        let recordStates = subTable.stateManager.checkedState.get(indexKey);
        recordStates || (recordStates = {}, subTable.stateManager.checkedState.set(indexKey, recordStates)), 
        recordStates[field] = checked;
    }));
    const checkboxCol = findCheckboxColumnIndex(subTable, field);
    if (checkboxCol >= 0) {
        subTable.scenegraph.updateHeaderCheckboxCellState(checkboxCol, 0, checked);
        for (let row = subTable.columnHeaderLevelCount; row < subTable.rowCount; row++) setCellCheckboxStateByAttribute(checkboxCol, row, checked, subTable);
    }
}