/*
 * Copyright (C) 2023-2024  Yomitan Authors
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

import {describe, expect, afterAll, test, vi} from 'vitest';
import {setupDomTest} from './fixtures/dom-test.js';
import {querySelectorNotNull} from '../ext/js/dom/query-selector.js';
import {SearchDisplayController} from '../ext/js/display/search-display-controller.js';
import {Display} from '../ext/js/display/display.js';
import {DisplayAudio} from '../ext/js/display/display-audio.js';
import {SearchPersistentStateController} from '../ext/js/display/search-persistent-state-controller.js';
import {Application} from '../ext/js/application.js';
import {CrossFrameAPI} from '../ext/js/comm/cross-frame-api.js';
import {API} from '../ext/js/comm/api.js';
import {DocumentFocusController} from '../ext/js/dom/document-focus-controller.js';
import {HotkeyHandler} from '../ext/js/input/hotkey-handler.js';
import {WebExtension} from '../ext/js/extension/web-extension.js';

const documentSearchDisplayControllerEnv = await setupDomTest('ext/search.html');

const {window, teardown} = documentSearchDisplayControllerEnv;

const {document} = window;

const frameId = 1;
const tabId = 1;
const webExtension = new WebExtension();
const hotkeyHandler = new HotkeyHandler();
const documentFocusController = new DocumentFocusController();
const displayPageType = 'search';
const api = new API(webExtension);
const crossFrameAPI = new CrossFrameAPI(api, tabId, frameId);
const application = new Application(api, crossFrameAPI);
const display = new Display(application, displayPageType, documentFocusController, hotkeyHandler);
const displayAudio = new DisplayAudio(display);
const searchPersistentStateController = new SearchPersistentStateController();

const searchDisplayController = new SearchDisplayController(display, displayAudio, searchPersistentStateController);

// eslint-disable-next-line no-underscore-dangle
const onKeyDownMethod = searchDisplayController._onKeyDown.bind(searchDisplayController);

/**
 * @type {HTMLInputElement}
 */
const queryInput = querySelectorNotNull(document, '#search-textbox');

const focusSpy = vi.spyOn(queryInput, 'focus');

describe('Keyboard Event Handling', () => {
    afterAll(() => teardown(global));

    const validKeypressEvents = [
        new KeyboardEvent('keydown', {key: 'a', ctrlKey: false, metaKey: false, altKey: false}),
        new KeyboardEvent('keydown', {key: 'Backspace'}),
        new KeyboardEvent('keydown', {key: 'Backspace', ctrlKey: true, metaKey: false, altKey: false}),
    ];

    const invalidKeypressEvents = [
        new KeyboardEvent('keydown', {key: '', ctrlKey: true, metaKey: false, altKey: false}),
        new KeyboardEvent('keydown', {key: '', ctrlKey: false, metaKey: true, altKey: false}),
        new KeyboardEvent('keydown', {key: '', ctrlKey: false, metaKey: false, altKey: true}),
        new KeyboardEvent('keydown', {key: ' ', ctrlKey: false, metaKey: false, altKey: false}),
        new KeyboardEvent('keydown', {key: 'a', ctrlKey: true, metaKey: false, altKey: false}),
        new KeyboardEvent('keydown', {key: 'a', ctrlKey: false, metaKey: true, altKey: false}),
        new KeyboardEvent('keydown', {key: 'a', ctrlKey: false, metaKey: false, altKey: true}),
        new KeyboardEvent('keydown', {key: 'Backspace', ctrlKey: false, metaKey: true, altKey: false}),
        new KeyboardEvent('keydown', {key: 'Backspace', ctrlKey: false, metaKey: false, altKey: true}),
        new KeyboardEvent('keydown', {key: 'ArrowDown'}),
    ];

    test('should test that onKeyDown function focuses input for valid keys', () => {
        for (const event of validKeypressEvents) {
            queryInput.blur();
            onKeyDownMethod(event);
        }

        expect(focusSpy.mock.calls.length).toBe(validKeypressEvents.length);
        focusSpy.mockReset();
    });


    test('should test that onKeyDown function does not focus input for invalid keys', () => {
        for (const event of invalidKeypressEvents) {
            queryInput.blur();
            onKeyDownMethod(event);
        }

        expect(focusSpy.mock.calls.length).toBe(0);
    });
});