import { Canvas, DisplayObject, } from '@antv/g';
import { each, get, hasIn, isEmpty, isFunction, isNil } from 'lodash';
import { GuiIcon, InteractionName } from '../common';
import { CellType, InteractionKeyboardKey, InterceptType, OriginEventType, S2Event, SHAPE_STYLE_MAP, } from '../common/constant';
import { CustomImage } from '../engine';
import { getSelectedData } from '../utils/export/copy';
import { keyEqualTo } from '../utils/export/method';
import { getAppendInfo } from '../utils/interaction/common';
import { isMobile } from '../utils/is-mobile';
import { verifyTheElementInTooltip } from '../utils/tooltip';
export class EventController {
    constructor(spreadsheet) {
        this.canvasEventHandlers = [];
        this.s2EventHandlers = [];
        this.domEventListeners = [];
        this.isCanvasEffect = false;
        // 不能单独判断是否 Image Shape, 用户如果自定义单元格绘制图片, 会导致判断错误
        this.isGuiIconShape = (target) => {
            return target instanceof CustomImage && target.imgType === GuiIcon.type;
        };
        this.isConditionIconShape = (target, cell) => {
            return cell
                .getConditionIconShapes()
                .some((shape) => { var _a; return (shape === null || shape === void 0 ? void 0 : shape.name) === ((_a = target === null || target === void 0 ? void 0 : target.attributes) === null || _a === void 0 ? void 0 : _a.name); });
        };
        this.onCanvasMousedown = (event) => {
            this.target = event.target;
            // 点击时清除 hover focus 状态
            this.spreadsheet.interaction.clearHoverTimer();
            if (this.isResizeArea(event)) {
                this.spreadsheet.emit(S2Event.LAYOUT_RESIZE_MOUSE_DOWN, event);
                // 仅捕获在 Canvas 之外触发的事件 https://github.com/antvis/S2/issues/1592
                const resizeMouseMoveCapture = (pointerEvent) => {
                    if (!this.spreadsheet.getCanvasElement()) {
                        return false;
                    }
                    if (this.spreadsheet.getCanvasElement() !== pointerEvent.target) {
                        this.spreadsheet.emit(S2Event.LAYOUT_RESIZE_MOUSE_MOVE, pointerEvent);
                    }
                };
                window.addEventListener(OriginEventType.POINTER_MOVE, resizeMouseMoveCapture);
                window.addEventListener(OriginEventType.POINTER_UP, () => {
                    window.removeEventListener(OriginEventType.POINTER_MOVE, resizeMouseMoveCapture);
                }, { once: true });
                return;
            }
            const cellType = this.spreadsheet.getCellType(event.target);
            switch (cellType) {
                case CellType.DATA_CELL:
                    this.spreadsheet.emit(S2Event.DATA_CELL_MOUSE_DOWN, event);
                    break;
                case CellType.ROW_CELL:
                    this.spreadsheet.emit(S2Event.ROW_CELL_MOUSE_DOWN, event);
                    break;
                case CellType.COL_CELL:
                    this.spreadsheet.emit(S2Event.COL_CELL_MOUSE_DOWN, event);
                    break;
                case CellType.CORNER_CELL:
                    this.spreadsheet.emit(S2Event.CORNER_CELL_MOUSE_DOWN, event);
                    break;
                case CellType.MERGED_CELL:
                    this.spreadsheet.emit(S2Event.MERGED_CELLS_MOUSE_DOWN, event);
                    break;
                default:
                    break;
            }
        };
        this.onCanvasMousemove = (event) => {
            this.canvasMousemoveEvent = event;
            if (this.isResizeArea(event)) {
                this.activeResizeArea(event);
                this.spreadsheet.emit(S2Event.LAYOUT_RESIZE_MOUSE_MOVE, event.nativeEvent);
                return;
            }
            this.resetResizeArea();
            const cell = this.spreadsheet.getCell(event.target);
            if (cell) {
                const cellType = cell.cellType;
                switch (cellType) {
                    case CellType.DATA_CELL:
                        this.spreadsheet.emit(S2Event.DATA_CELL_MOUSE_MOVE, event);
                        break;
                    case CellType.ROW_CELL:
                        this.spreadsheet.emit(S2Event.ROW_CELL_MOUSE_MOVE, event);
                        break;
                    case CellType.COL_CELL:
                        this.spreadsheet.emit(S2Event.COL_CELL_MOUSE_MOVE, event);
                        break;
                    case CellType.CORNER_CELL:
                        this.spreadsheet.emit(S2Event.CORNER_CELL_MOUSE_MOVE, event);
                        break;
                    case CellType.MERGED_CELL:
                        this.spreadsheet.emit(S2Event.MERGED_CELLS_MOUSE_MOVE, event);
                        break;
                    default:
                        break;
                }
                if (!this.hasBrushSelectionIntercepts()) {
                    this.spreadsheet.emit(S2Event.GLOBAL_HOVER, event);
                    switch (cellType) {
                        case CellType.DATA_CELL:
                            this.spreadsheet.emit(S2Event.DATA_CELL_HOVER, event);
                            break;
                        case CellType.ROW_CELL:
                            this.spreadsheet.emit(S2Event.ROW_CELL_HOVER, event);
                            break;
                        case CellType.COL_CELL:
                            this.spreadsheet.emit(S2Event.COL_CELL_HOVER, event);
                            break;
                        case CellType.CORNER_CELL:
                            this.spreadsheet.emit(S2Event.CORNER_CELL_HOVER, event);
                            break;
                        case CellType.MERGED_CELL:
                            this.spreadsheet.emit(S2Event.MERGED_CELLS_HOVER, event);
                            break;
                        default:
                            break;
                    }
                }
            }
        };
        this.onCanvasMouseup = (event) => {
            if (this.isResizeArea(event)) {
                this.spreadsheet.emit(S2Event.LAYOUT_RESIZE_MOUSE_UP, event);
                return;
            }
            const cell = this.spreadsheet.getCell(event.target);
            if (cell) {
                const cellType = cell.cellType;
                // 通用的 mouseup 事件
                switch (cellType) {
                    case CellType.DATA_CELL:
                        this.spreadsheet.emit(S2Event.DATA_CELL_MOUSE_UP, event);
                        break;
                    case CellType.ROW_CELL:
                        this.spreadsheet.emit(S2Event.ROW_CELL_MOUSE_UP, event);
                        break;
                    case CellType.COL_CELL:
                        this.spreadsheet.emit(S2Event.COL_CELL_MOUSE_UP, event);
                        break;
                    case CellType.CORNER_CELL:
                        this.spreadsheet.emit(S2Event.CORNER_CELL_MOUSE_UP, event);
                        break;
                    case CellType.MERGED_CELL:
                        this.spreadsheet.emit(S2Event.MERGED_CELLS_MOUSE_UP, event);
                        break;
                    default:
                        break;
                }
                if (isMobile()) {
                    // Mobile场景下单击走这里
                    this.onCanvasSingleClick(event);
                }
            }
        };
        this.onCanvasClick = (event) => {
            const spreadsheet = this.spreadsheet;
            if (event.detail === 1 && !isMobile()) {
                // PC场景下单击走这里
                this.onCanvasSingleClick(event);
                return;
            }
            if (event.detail !== 2) {
                return;
            }
            if (this.isResizeArea(event)) {
                spreadsheet.emit(S2Event.LAYOUT_RESIZE_MOUSE_UP, event);
                return;
            }
            spreadsheet.emit(S2Event.GLOBAL_DOUBLE_CLICK, event);
            const cell = spreadsheet.getCell(event.target);
            if (cell) {
                const cellType = cell.cellType;
                if (this.target === event.target) {
                    switch (cellType) {
                        case CellType.DATA_CELL:
                            spreadsheet.emit(S2Event.DATA_CELL_DOUBLE_CLICK, event);
                            break;
                        case CellType.ROW_CELL:
                            spreadsheet.emit(S2Event.ROW_CELL_DOUBLE_CLICK, event);
                            break;
                        case CellType.COL_CELL:
                            spreadsheet.emit(S2Event.COL_CELL_DOUBLE_CLICK, event);
                            break;
                        case CellType.CORNER_CELL:
                            spreadsheet.emit(S2Event.CORNER_CELL_DOUBLE_CLICK, event);
                            break;
                        case CellType.MERGED_CELL:
                            spreadsheet.emit(S2Event.MERGED_CELLS_DOUBLE_CLICK, event);
                            break;
                        default:
                            break;
                    }
                }
            }
        };
        this.onCanvasMouseout = (event) => {
            if (!this.isAutoResetSheetStyle(event) ||
                this.isMouseOnTheCanvasContainer(event)) {
                return;
            }
            const { interaction } = this.spreadsheet;
            // 两种情况不能重置 1. 选中单元格 2. 有 intercepts 时（重置会清空 intercepts）
            if (!interaction.isSelectedState() && !(interaction.intercepts.size > 0)) {
                interaction.reset();
            }
        };
        this.onCanvasContextMenu = (event) => {
            const spreadsheet = this.spreadsheet;
            if (this.isResizeArea(event)) {
                spreadsheet.emit(S2Event.LAYOUT_RESIZE_MOUSE_UP, event);
                return;
            }
            spreadsheet.emit(S2Event.GLOBAL_CONTEXT_MENU, event);
            const cellType = this.spreadsheet.getCellType(event.target);
            switch (cellType) {
                case CellType.DATA_CELL:
                    this.spreadsheet.emit(S2Event.DATA_CELL_CONTEXT_MENU, event);
                    break;
                case CellType.ROW_CELL:
                    this.spreadsheet.emit(S2Event.ROW_CELL_CONTEXT_MENU, event);
                    break;
                case CellType.COL_CELL:
                    this.spreadsheet.emit(S2Event.COL_CELL_CONTEXT_MENU, event);
                    break;
                case CellType.CORNER_CELL:
                    this.spreadsheet.emit(S2Event.CORNER_CELL_CONTEXT_MENU, event);
                    break;
                case CellType.MERGED_CELL:
                    this.spreadsheet.emit(S2Event.MERGED_CELLS_CONTEXT_MENU, event);
                    break;
                default:
                    break;
            }
        };
        this.spreadsheet = spreadsheet;
        this.bindEvents();
    }
    get canvasContainer() {
        return this.spreadsheet.container;
    }
    isAutoResetSheetStyle(event) {
        var _a;
        const { interaction } = this.spreadsheet.options;
        return isFunction(interaction === null || interaction === void 0 ? void 0 : interaction.autoResetSheetStyle)
            ? (_a = interaction === null || interaction === void 0 ? void 0 : interaction.autoResetSheetStyle) === null || _a === void 0 ? void 0 : _a.call(interaction, event, this.spreadsheet)
            : interaction === null || interaction === void 0 ? void 0 : interaction.autoResetSheetStyle;
    }
    bindEvents() {
        this.clearAllEvents();
        // canvas events
        this.addCanvasEvent(OriginEventType.MOUSE_DOWN, this.onCanvasMousedown);
        this.addCanvasEvent(OriginEventType.TOUCH_START, (event) => {
            this.target = event.target;
        });
        const realClickEvent = isMobile()
            ? OriginEventType.TOUCH_END
            : OriginEventType.POINTER_UP;
        this.addCanvasEvent(OriginEventType.POINTER_MOVE, this.onCanvasMousemove);
        this.addCanvasEvent(OriginEventType.MOUSE_OUT, this.onCanvasMouseout);
        this.addCanvasEvent(realClickEvent, this.onCanvasMouseup);
        this.addCanvasEvent(OriginEventType.CLICK, this.onCanvasClick);
        /**
         * 如果监听 G Canvas, 右键对应的是 rightup/rightdown 事件, 如需禁用右键菜单 (preventDefault), 需要监听 DOM
         * https://g.antv.antgroup.com/api/event/faq#%E7%A6%81%E7%94%A8%E5%8F%B3%E9%94%AE%E8%8F%9C%E5%8D%95
         */
        this.addCanvasEvent(OriginEventType.RIGHT_DOWN, this.onCanvasContextMenu);
        // spreadsheet events
        this.addS2Event(S2Event.GLOBAL_ACTION_ICON_CLICK, () => {
            this.spreadsheet.interaction.addIntercepts([InterceptType.HOVER]);
            this.spreadsheet.interaction.clearState();
        });
        // dom events
        this.addDomEventListener(window, OriginEventType.CLICK, (event) => {
            this.resetSheetStyle(event);
            this.isCanvasEffect = this.isMouseOnTheCanvasContainer(event);
        });
        this.addDomEventListener(window, OriginEventType.KEY_DOWN, (event) => {
            this.onKeyboardCopy(event);
            this.onKeyboardEsc(event);
            this.spreadsheet.emit(S2Event.GLOBAL_KEYBOARD_DOWN, event);
        });
        this.addDomEventListener(window, OriginEventType.KEY_UP, (event) => {
            this.spreadsheet.emit(S2Event.GLOBAL_KEYBOARD_UP, event);
        });
        this.addDomEventListener(window, OriginEventType.POINTER_UP, (event) => {
            this.spreadsheet.emit(S2Event.GLOBAL_MOUSE_UP, event);
        });
        this.addDomEventListener(window, OriginEventType.POINTER_MOVE, (event) => {
            this.spreadsheet.emit(S2Event.GLOBAL_MOUSE_MOVE, event);
        });
    }
    // Windows and Mac OS
    onKeyboardCopy(event) {
        const { copy } = this.spreadsheet.options.interaction;
        if (this.isCanvasEffect &&
            (copy === null || copy === void 0 ? void 0 : copy.enable) &&
            keyEqualTo(event.key, InteractionKeyboardKey.COPY) &&
            (event.metaKey || event.ctrlKey)) {
            const copyData = getSelectedData(this.spreadsheet);
            if (!isNil(copyData)) {
                this.spreadsheet.emit(S2Event.GLOBAL_COPIED, copyData);
            }
        }
    }
    onKeyboardEsc(event) {
        if (this.isCanvasEffect &&
            keyEqualTo(event.key, InteractionKeyboardKey.ESC)) {
            this.resetSheetStyle(event);
        }
    }
    resetSheetStyle(event) {
        var _a, _b;
        if (!this.isAutoResetSheetStyle(event) || !this.spreadsheet) {
            return;
        }
        /**
         * 全局有 mouseUp 和 click 事件, 当刷选完成后会同时触发, 当选中单元格后, 会同时触发 click 对应的 reset 事件
         * 所以如果是 刷选过程中 引起的 click(mousedown + mouseup) 事件, 则不需要重置
         */
        const { interaction } = this.spreadsheet;
        if ((_a = interaction === null || interaction === void 0 ? void 0 : interaction.hasIntercepts) === null || _a === void 0 ? void 0 : _a.call(interaction, [
            InterceptType.DATA_CELL_BRUSH_SELECTION,
            InterceptType.COL_CELL_BRUSH_SELECTION,
            InterceptType.ROW_CELL_BRUSH_SELECTION,
        ])) {
            (_b = interaction === null || interaction === void 0 ? void 0 : interaction.removeIntercepts) === null || _b === void 0 ? void 0 : _b.call(interaction, [
                InterceptType.DATA_CELL_BRUSH_SELECTION,
                InterceptType.ROW_CELL_BRUSH_SELECTION,
                InterceptType.COL_CELL_BRUSH_SELECTION,
            ]);
            return;
        }
        if (this.isMouseOnTheTooltip(event) ||
            this.isMouseOnTheCanvasContainer(event)) {
            return;
        }
        interaction.reset();
        this.spreadsheet.emit(S2Event.GLOBAL_RESET, event);
        this.spreadsheet.emit(S2Event.GLOBAL_SELECTED, interaction.getActiveCells(), {
            event,
            targetCell: null,
            interactionName: InteractionName.GLOBAL_RESET,
        });
    }
    isMouseEvent(event) {
        // 通过 MouseEvent 特有属性判断，避免 instanceof 失效的问题
        return hasIn(event, 'clientX') && hasIn(event, 'clientY');
    }
    isMatchElement(event) {
        const canvas = this.spreadsheet.getCanvasElement();
        const { target } = event;
        return (target === canvas ||
            target instanceof DisplayObject ||
            target instanceof Canvas);
    }
    isMatchPoint(event) {
        /**
         * 这里不能使用 bounding rect 的 width 和 height, 高清适配后 canvas 实际宽高会变
         * 比如实际 400 * 300 => hd (800 * 600)
         * 从视觉来看, 虽然点击了空白处, 但其实还是处于 放大后的 canvas 区域, 所以还需要额外判断一下坐标
         */
        const canvas = this.spreadsheet.getCanvasElement();
        const { width, height } = this.getContainerRect();
        const { x, y } = canvas.getBoundingClientRect() || {};
        const { clientX, clientY } = event;
        return (clientX <= x + width &&
            clientX >= x &&
            clientY <= y + height &&
            clientY >= y);
    }
    isMouseOnTheCanvasContainer(event) {
        if (this.isMouseEvent(event)) {
            const canvas = this.spreadsheet.getCanvasElement();
            if (!canvas) {
                return false;
            }
            // 开启 CSS transform 时, 降级处理, 不做 canvas 内的空白检测: https://github.com/antvis/S2/issues/2879
            if (this.spreadsheet.getCanvasConfig().supportsCSSTransform) {
                return this.isMatchElement(event);
            }
            return this.isMatchElement(event) && this.isMatchPoint(event);
        }
        return false;
    }
    getContainerRect() {
        var _a;
        const { facet, options } = this.spreadsheet;
        const scrollBar = (facet === null || facet === void 0 ? void 0 : facet.hRowScrollBar) || (facet === null || facet === void 0 ? void 0 : facet.hScrollBar);
        const { maxX, maxY } = (facet === null || facet === void 0 ? void 0 : facet.panelBBox) || {};
        const { width = 0, height = 0 } = options;
        /**
         * https://github.com/antvis/S2/issues/2376
         * 横向的滚动条在表格外 (Canvas 内), 点击滚动条(含滑道区域) 不应该重置交互
         */
        const trackHeight = ((_a = scrollBar === null || scrollBar === void 0 ? void 0 : scrollBar.theme) === null || _a === void 0 ? void 0 : _a.size) || 0;
        return {
            width: Math.min(width, maxX),
            height: Math.min(height, maxY + trackHeight),
        };
    }
    isMouseOnTheTooltip(event) {
        var _a, _b, _c, _d;
        const { tooltip } = this.spreadsheet;
        if (!(tooltip === null || tooltip === void 0 ? void 0 : tooltip.visible)) {
            return false;
        }
        const { x, y, width, height } = ((_c = (_b = (_a = this.spreadsheet.tooltip) === null || _a === void 0 ? void 0 : _a.container) === null || _b === void 0 ? void 0 : _b.getBoundingClientRect) === null || _c === void 0 ? void 0 : _c.call(_b)) || {};
        if (event.target instanceof Node) {
            return verifyTheElementInTooltip((_d = this.spreadsheet.tooltip) === null || _d === void 0 ? void 0 : _d.container, event.target);
        }
        if (this.isMouseEvent(event)) {
            return (event.clientX >= x &&
                event.clientX <= x + width &&
                event.clientY >= y &&
                event.clientY <= y + height);
        }
        return false;
    }
    isResizeArea(event) {
        const appendInfo = getAppendInfo(event.target);
        return appendInfo === null || appendInfo === void 0 ? void 0 : appendInfo.isResizeArea;
    }
    activeResizeArea(event) {
        var _a, _b, _c;
        const appendInfo = get(event.target, 'attrs.appendInfo');
        if (appendInfo === null || appendInfo === void 0 ? void 0 : appendInfo.isResizeMask) {
            return;
        }
        this.resetResizeArea();
        const resizeArea = event.target;
        this.spreadsheet.store.set('activeResizeArea', resizeArea);
        resizeArea.attr(SHAPE_STYLE_MAP.backgroundOpacity, (_c = (_b = (_a = this.spreadsheet.theme.resizeArea) === null || _a === void 0 ? void 0 : _a.interactionState) === null || _b === void 0 ? void 0 : _b.hover) === null || _c === void 0 ? void 0 : _c.backgroundOpacity);
    }
    resetResizeArea() {
        var _a;
        const resizeArea = this.spreadsheet.store.get('activeResizeArea');
        if (!isEmpty(resizeArea)) {
            resizeArea.attr(SHAPE_STYLE_MAP.backgroundOpacity, (_a = this.spreadsheet.theme.resizeArea) === null || _a === void 0 ? void 0 : _a.backgroundOpacity);
        }
        this.spreadsheet.store.set('activeResizeArea', resizeArea);
    }
    hasBrushSelectionIntercepts() {
        return this.spreadsheet.interaction.hasIntercepts([
            InterceptType.HOVER,
            InterceptType.DATA_CELL_BRUSH_SELECTION,
            InterceptType.ROW_CELL_BRUSH_SELECTION,
            InterceptType.COL_CELL_BRUSH_SELECTION,
        ]);
    }
    onCanvasSingleClick(event) {
        const cell = this.spreadsheet.getCell(event.target);
        // target 相同，说明是一个 cell 内的 click 事件
        if (this.target === event.target && cell) {
            // 屏蔽 actionIcons 的点击，字段标记增加的 icon 除外.
            if (this.isGuiIconShape(event.target) &&
                !this.isConditionIconShape(event.target, cell)) {
                return;
            }
            this.spreadsheet.emit(S2Event.GLOBAL_CLICK, event);
            switch (cell.cellType) {
                case CellType.DATA_CELL:
                    this.spreadsheet.emit(S2Event.DATA_CELL_CLICK, event);
                    break;
                case CellType.ROW_CELL:
                    this.spreadsheet.emit(S2Event.ROW_CELL_CLICK, event);
                    break;
                case CellType.COL_CELL:
                    this.spreadsheet.emit(S2Event.COL_CELL_CLICK, event);
                    break;
                case CellType.CORNER_CELL:
                    this.spreadsheet.emit(S2Event.CORNER_CELL_CLICK, event);
                    break;
                case CellType.MERGED_CELL:
                    this.spreadsheet.emit(S2Event.MERGED_CELLS_CLICK, event);
                    break;
                default:
                    break;
            }
        }
    }
    clear() {
        this.unbindEvents();
    }
    unbindEvents() {
        this.clearAllEvents();
    }
    addCanvasEvent(eventType, handler) {
        var _a;
        (_a = this.canvasContainer) === null || _a === void 0 ? void 0 : _a.on(eventType, handler);
        this.canvasEventHandlers.push({ type: eventType, handler });
    }
    addS2Event(eventType, handler) {
        this.spreadsheet.on(eventType, handler);
        this.s2EventHandlers.push({
            type: eventType,
            handler,
        });
    }
    addDomEventListener(target, type, handler) {
        if (target.addEventListener) {
            const { eventListenerOptions } = this.spreadsheet.options.interaction;
            target.addEventListener(type, handler, eventListenerOptions);
            this.domEventListeners.push({
                target,
                type,
                handler: handler,
                options: eventListenerOptions,
            });
        }
        else {
            // eslint-disable-next-line no-console
            console.error(`Please make sure ${target} has addEventListener function`);
        }
    }
    clearAllEvents() {
        each(this.canvasEventHandlers, ({ type, handler }) => {
            var _a;
            (_a = this.canvasContainer) === null || _a === void 0 ? void 0 : _a.removeEventListener(type, handler);
        });
        each(this.s2EventHandlers, ({ type, handler }) => {
            this.spreadsheet.off(type, handler);
        });
        each(this.domEventListeners, (listener) => {
            listener.target.removeEventListener(listener.type, listener.handler, listener.options);
        });
        this.canvasEventHandlers = [];
        this.s2EventHandlers = [];
        this.domEventListeners = [];
    }
    getViewportPoint(event) {
        const config = this.spreadsheet.getCanvasConfig();
        // https://github.com/antvis/G/blob/a43c19a662684945d0bf9dc1876af43ac26b1243/packages/g-lite/src/plugins/EventPlugin.ts#L216
        if (config.supportsCSSTransform &&
            !isNil(event.offsetX) &&
            !isNil(event.offsetY)) {
            return {
                x: event.offsetX,
                y: event.offsetY,
            };
        }
        return this.spreadsheet.container.client2Viewport({
            x: event.clientX,
            y: event.clientY,
        });
    }
}
//# sourceMappingURL=event-controller.js.map