"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const react_2 = require("@testing-library/react");
const MessageBox_1 = require("./MessageBox");
const user_event_1 = __importDefault(require("@testing-library/user-event"));
describe('MessageBox', () => {
    beforeEach(() => {
        jest.spyOn(window, 'requestAnimationFrame').mockImplementation((cb) => {
            cb(0); // Immediately call the callback
            return 0;
        });
    });
    afterEach(() => {
        jest.restoreAllMocks();
    });
    it('should render Message box', () => {
        (0, react_2.render)((0, jsx_runtime_1.jsx)(MessageBox_1.MessageBox, { children: (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: "Chatbot Messages" }) }));
        expect(react_2.screen.getByText('Chatbot Messages')).toBeTruthy();
    });
    it('should assign ref to Message box', () => {
        var _a, _b, _c, _d;
        const ref = (0, react_1.createRef)();
        (0, react_2.render)((0, jsx_runtime_1.jsx)(MessageBox_1.MessageBox, { "data-testid": "message-box", ref: ref, children: (0, jsx_runtime_1.jsx)("div", { children: "Test message content" }) }));
        react_2.screen.getByText('Test message content');
        expect(ref.current).not.toBeNull();
        // should contain custom methods exposed by the ref
        expect(typeof ((_a = ref.current) === null || _a === void 0 ? void 0 : _a.isSmartScrollActive)).toBe('function');
        expect(typeof ((_b = ref.current) === null || _b === void 0 ? void 0 : _b.scrollToTop)).toBe('function');
        expect(typeof ((_c = ref.current) === null || _c === void 0 ? void 0 : _c.scrollToBottom)).toBe('function');
        expect((_d = ref.current) === null || _d === void 0 ? void 0 : _d.isSmartScrollActive()).toBe(false);
        expect(ref.current).toBeInstanceOf(HTMLDivElement);
    });
    it('should call onScrollToBottomClick when scroll to bottom button is clicked', () => __awaiter(void 0, void 0, void 0, function* () {
        const spy = jest.fn();
        (0, react_2.render)((0, jsx_runtime_1.jsx)(MessageBox_1.MessageBox, { onScrollToBottomClick: spy, children: (0, jsx_runtime_1.jsx)("div", { children: "Test message content" }) }));
        // this forces button to show
        const region = react_2.screen.getByRole('region');
        Object.defineProperty(region, 'scrollHeight', { configurable: true, value: 1000 });
        Object.defineProperty(region, 'clientHeight', { configurable: true, value: 500 });
        Object.defineProperty(region, 'scrollTop', { configurable: true, value: 0 });
        (0, react_2.act)(() => {
            region.dispatchEvent(new Event('scroll'));
        });
        yield (0, react_2.waitFor)(() => {
            user_event_1.default.click(react_2.screen.getByRole('button', { name: /Back to bottom/i }));
            expect(spy).toHaveBeenCalled();
        });
    }));
    it('should call onScrollToTopClick when scroll to top button is clicked', () => __awaiter(void 0, void 0, void 0, function* () {
        const spy = jest.fn();
        (0, react_2.render)((0, jsx_runtime_1.jsx)(MessageBox_1.MessageBox, { onScrollToTopClick: spy, children: (0, jsx_runtime_1.jsx)("div", { children: "Test message content" }) }));
        // this forces button to show
        const region = react_2.screen.getByRole('region');
        Object.defineProperty(region, 'scrollHeight', { configurable: true, value: 1000 });
        Object.defineProperty(region, 'clientHeight', { configurable: true, value: 500 });
        Object.defineProperty(region, 'scrollTop', {
            configurable: true,
            value: 500
        });
        (0, react_2.act)(() => {
            region.dispatchEvent(new Event('scroll'));
        });
        yield (0, react_2.waitFor)(() => {
            user_event_1.default.click(react_2.screen.getByRole('button', { name: /Back to top/i }));
            expect(spy).toHaveBeenCalled();
        });
    }));
    it('should call user defined onWheel, onTouchMove and onTouchEnd handlers', () => __awaiter(void 0, void 0, void 0, function* () {
        const ref = (0, react_1.createRef)();
        const onWheel = jest.fn();
        const onTouchMove = jest.fn();
        const onTouchEnd = jest.fn();
        (0, react_2.render)((0, jsx_runtime_1.jsx)(MessageBox_1.MessageBox, { ref: ref, enableSmartScroll: true, onWheel: onWheel, onTouchMove: onTouchMove, onTouchEnd: onTouchEnd, children: (0, jsx_runtime_1.jsx)("div", { children: "Test message content" }) }));
        const element = ref.current;
        (0, react_2.act)(() => {
            react_2.fireEvent.wheel(element, { deltaY: 10 });
            react_2.fireEvent.touchMove(element, { touches: [{ clientY: 700 }] });
            react_2.fireEvent.touchEnd(element);
        });
        expect(onWheel).toHaveBeenCalled();
        expect(onTouchMove).toHaveBeenCalled();
        expect(onTouchEnd).toHaveBeenCalled();
    }));
    it('should scroll to the bottom when the method is called ', () => __awaiter(void 0, void 0, void 0, function* () {
        var _a;
        const ref = (0, react_1.createRef)();
        (0, react_2.render)((0, jsx_runtime_1.jsx)(MessageBox_1.MessageBox, { ref: ref, enableSmartScroll: true, children: (0, jsx_runtime_1.jsx)("div", { children: "Test message content" }) }));
        const element = ref.current;
        const scrollSpy = jest.spyOn(element, 'scrollTo');
        (0, react_2.act)(() => {
            var _a, _b, _c;
            (_a = ref.current) === null || _a === void 0 ? void 0 : _a.scrollToBottom();
            (_b = ref.current) === null || _b === void 0 ? void 0 : _b.scrollToBottom();
            (_c = ref.current) === null || _c === void 0 ? void 0 : _c.scrollToBottom();
        });
        expect(scrollSpy).toHaveBeenCalledWith({ top: element.scrollHeight, behavior: 'smooth' });
        expect((_a = ref.current) === null || _a === void 0 ? void 0 : _a.isSmartScrollActive()).toBe(true);
    }));
    it('should scroll to the top when the method is called ', () => __awaiter(void 0, void 0, void 0, function* () {
        var _a;
        const ref = (0, react_1.createRef)();
        (0, react_2.render)((0, jsx_runtime_1.jsx)(MessageBox_1.MessageBox, { ref: ref, enableSmartScroll: true, children: (0, jsx_runtime_1.jsx)("div", { children: "Test message content" }) }));
        const element = ref.current;
        const scrollSpy = jest.spyOn(element, 'scrollTo');
        (0, react_2.act)(() => {
            var _a;
            (_a = ref.current) === null || _a === void 0 ? void 0 : _a.scrollToTop();
        });
        expect(scrollSpy).toHaveBeenCalledWith({ top: 0, behavior: 'smooth' });
        expect((_a = ref.current) === null || _a === void 0 ? void 0 : _a.isSmartScrollActive()).toBe(false);
    }));
    it('should pause automatic scrolling when user scrolls up ', () => __awaiter(void 0, void 0, void 0, function* () {
        var _a, _b;
        const ref = (0, react_1.createRef)();
        (0, react_2.render)((0, jsx_runtime_1.jsx)(MessageBox_1.MessageBox, { ref: ref, enableSmartScroll: true, children: (0, jsx_runtime_1.jsx)("div", { children: "Test message content" }) }));
        expect((_a = ref.current) === null || _a === void 0 ? void 0 : _a.isSmartScrollActive()).toBe(true);
        const element = ref.current;
        // Manually set scrollHeight and clientHeight for calculations
        Object.defineProperty(element, 'scrollHeight', { configurable: true, value: 1000 });
        Object.defineProperty(element, 'clientHeight', { configurable: true, value: 300 });
        // Simulate scroll up by changing scrollTop
        element.scrollTop = 200;
        const scrollEvent = new Event('scroll', { bubbles: true });
        (0, react_2.act)(() => {
            element.dispatchEvent(scrollEvent);
        });
        expect((_b = ref.current) === null || _b === void 0 ? void 0 : _b.isSmartScrollActive()).toBe(false);
    }));
    it('should resume automatic scrolling when user scrolls down to the bottom using scroll event', () => __awaiter(void 0, void 0, void 0, function* () {
        var _a, _b;
        jest.useFakeTimers();
        const ref = (0, react_1.createRef)();
        (0, react_2.render)((0, jsx_runtime_1.jsx)(MessageBox_1.MessageBox, { ref: ref, enableSmartScroll: true, children: (0, jsx_runtime_1.jsx)("div", { children: "Test message content" }) }));
        const element = ref.current;
        // Manually set scrollHeight and clientHeight for calculations
        Object.defineProperty(element, 'scrollHeight', { configurable: true, value: 1000 });
        Object.defineProperty(element, 'clientHeight', { configurable: true, value: 300 });
        // Simulate scroll up by changing scrollTop
        element.scrollTop = 100;
        const scrollEvent = new Event('scroll', { bubbles: true });
        (0, react_2.act)(() => {
            element.dispatchEvent(scrollEvent);
        });
        expect((_a = ref.current) === null || _a === void 0 ? void 0 : _a.isSmartScrollActive()).toBe(false);
        (0, react_2.act)(() => {
            // Simulate scroll down by changing scrollTop
            element.scrollTop = 650; // scrollHeight - scrollTop - clientHeight - DELTA_DOWN (50) = 0
            const scrollEvent = new Event('scroll', { bubbles: true });
            element.dispatchEvent(scrollEvent);
            jest.advanceTimersByTime(250);
        });
        expect((_b = ref.current) === null || _b === void 0 ? void 0 : _b.isSmartScrollActive()).toBe(true);
        jest.useRealTimers();
    }));
    it('should resume automatic scrolling when scrollToBottom method is used', () => __awaiter(void 0, void 0, void 0, function* () {
        var _a, _b;
        const ref = (0, react_1.createRef)();
        (0, react_2.render)((0, jsx_runtime_1.jsx)(MessageBox_1.MessageBox, { ref: ref, enableSmartScroll: true, children: (0, jsx_runtime_1.jsx)("div", { children: "Test message content" }) }));
        const element = ref.current;
        // Manually set scrollHeight and clientHeight for calculations
        Object.defineProperty(element, 'scrollHeight', { configurable: true, value: 1000 });
        Object.defineProperty(element, 'clientHeight', { configurable: true, value: 300 });
        // Simulate scroll up by changing scrollTop
        element.scrollTop = 100;
        const scrollEvent = new Event('scroll', { bubbles: true });
        (0, react_2.act)(() => {
            element.dispatchEvent(scrollEvent);
        });
        expect((_a = ref.current) === null || _a === void 0 ? void 0 : _a.isSmartScrollActive()).toBe(false);
        (0, react_2.act)(() => {
            var _a;
            (_a = ref.current) === null || _a === void 0 ? void 0 : _a.scrollToBottom({ resumeSmartScroll: true, behavior: 'auto' }); // resumes auto scroll and scrolls to bottom.
        });
        expect((_b = ref.current) === null || _b === void 0 ? void 0 : _b.isSmartScrollActive()).toBe(true);
    }));
    it('should resume automatic scrolling when mouse wheel event is used', () => __awaiter(void 0, void 0, void 0, function* () {
        var _a, _b;
        const ref = (0, react_1.createRef)();
        (0, react_2.render)((0, jsx_runtime_1.jsx)(MessageBox_1.MessageBox, { ref: ref, enableSmartScroll: true, children: (0, jsx_runtime_1.jsx)("div", { children: "Test message content" }) }));
        const element = ref.current;
        // Manually set scrollHeight and clientHeight for calculations
        Object.defineProperty(element, 'scrollHeight', { configurable: true, value: 1000 });
        Object.defineProperty(element, 'clientHeight', { configurable: true, value: 300 });
        Object.defineProperty(element, 'scrollTop', { configurable: true, value: 350 });
        const scrollEvent = new Event('scroll', { bubbles: true });
        (0, react_2.act)(() => {
            element.dispatchEvent(scrollEvent);
        });
        expect((_a = ref.current) === null || _a === void 0 ? void 0 : _a.isSmartScrollActive()).toBe(false);
        // Simulate mouse wheel event
        (0, react_2.act)(() => {
            Object.defineProperty(element, 'scrollTop', { configurable: true, value: 650 });
            react_2.fireEvent.wheel(element, { deltaY: 10 });
        });
        expect((_b = ref.current) === null || _b === void 0 ? void 0 : _b.isSmartScrollActive()).toBe(true);
    }));
    it('should resume automatic scrolling when user swipes up in touch screen', () => __awaiter(void 0, void 0, void 0, function* () {
        var _a, _b;
        const ref = (0, react_1.createRef)();
        (0, react_2.render)((0, jsx_runtime_1.jsx)(MessageBox_1.MessageBox, { ref: ref, enableSmartScroll: true, children: (0, jsx_runtime_1.jsx)("div", { children: "Test message content" }) }));
        const element = ref.current;
        // Manually set scrollHeight and clientHeight for calculations
        Object.defineProperty(element, 'scrollHeight', { configurable: true, value: 1000 });
        Object.defineProperty(element, 'clientHeight', { configurable: true, value: 300 });
        Object.defineProperty(element, 'scrollTop', { configurable: true, value: 350 });
        const scrollEvent = new Event('scroll', { bubbles: true });
        (0, react_2.act)(() => {
            element.dispatchEvent(scrollEvent);
        });
        expect((_a = ref.current) === null || _a === void 0 ? void 0 : _a.isSmartScrollActive()).toBe(false);
        // Simulate touch event - swipe up
        (0, react_2.act)(() => {
            Object.defineProperty(element, 'scrollTop', { configurable: true, value: 650 });
            react_2.fireEvent.touchStart(element, { touches: [{ clientY: 700 }] });
            react_2.fireEvent.touchMove(element, { touches: [{ clientY: 700 }] });
            react_2.fireEvent.touchMove(element, { touches: [{ clientY: 600 }] });
            react_2.fireEvent.touchEnd(element);
        });
        expect((_b = ref.current) === null || _b === void 0 ? void 0 : _b.isSmartScrollActive()).toBe(true);
    }));
});
