/* Created by staff of the U.S. Securities and Exchange Commission.
 * Data and content created by government employees within the scope of their employment
 * are not subject to domestic copyright protection. 17 U.S.C. 105.
 */

import { FactsChart } from "./facts/chart";
import { FactsMenu } from "./facts/menu";
import { FactsTable } from "./facts/table";
import { FormInformation } from "./form-information/form-information";
import { Modals } from "./modals/modals";
import { ModalsFormInformation } from "./modals/form-information";
import { ModalsSettings } from "./modals/settings";
import { Search } from "./search/search";
import { SectionsSearch } from "./sections/sectionSearch";
import { UserFiltersDataRadios } from "./user-filters/data-radios";
import { UserFiltersDropdown } from "./user-filters/dropdown";
import { UserFiltersGeneral } from "./user-filters/general";
import { UserFiltersMoreFiltersBalances } from "./user-filters/more-filters-balance";
import { UserFiltersTagsRadios } from "./user-filters/tags-radios";
import { actionKeyHandler, stopPropPrevDefault } from "./helpers/utils";
import { Constants } from "./constants/constants";
import { ConstantsFunctions } from "./constants/functions";
import { HelpersUrl } from "./helpers/url";

export class Listeners {
    constructor() {
        this.init();
    }
    init() {
        Constants.appWindow.addEventListener('popstate', () => {
            /*
                Because we are circumventing default back/forward behavior in browser (in order to prevent full, time-expensive reload),
                We must tell any app loading functions that loading is triggered from back action, so they don't push another state to history.
                We accomplished with passing boolean "onBack" to changeInstance() and switchDoc()
            */
            const poppedUrlQueryString = Constants.appWindow.location.search;
            const newStateDoc = Constants.getInlineFiles.filter(file => poppedUrlQueryString.includes(file.slug))[0];

            if (newStateDoc) {
                if (!newStateDoc.current) {
                    ConstantsFunctions.switchDoc(newStateDoc.slug, true).then(() => Constants.appWindow.focus());
                }
            }
            // newStateDoc in another instance
            else {
                const instances = Constants.getInstances;
                const targetDoc = HelpersUrl.getDocFromSearchParam(Constants.appWindow.location.search);
                const instanceToChangeTo = instances.find(inst => {
                    return inst.docs.find(doc => doc.slug === targetDoc);
                })
                if (instanceToChangeTo) {
                    ConstantsFunctions.changeInstance(instanceToChangeTo.instance, targetDoc, true);
                }
            }
        });

        document.getElementById('menu-dropdown-information')?.addEventListener('click', (event: MouseEvent) => {
            ModalsFormInformation.clickEvent(event);
        });
        document.getElementById('menu-dropdown-information')?.addEventListener('keyup', (event: KeyboardEvent) => {
            if (!actionKeyHandler(event)) return;
            ModalsFormInformation.clickEvent(event);
        });

        document.getElementById('menu-dropdown-link')?.addEventListener('click', () => {
            FormInformation.init();
        });
        document.getElementById('menu-dropdown-link')?.addEventListener('keyup', () => {
            FormInformation.init();
        });

        document.getElementById('menu-dropdown-settings')?.addEventListener('click', (event: MouseEvent) => {
            ModalsSettings.clickEvent(event);
        });
        document.getElementById('menu-dropdown-settings')?.addEventListener('keyup', (event: KeyboardEvent) => {
            if (!actionKeyHandler(event)) return;
            ModalsSettings.clickEvent(event);
        });

        document.getElementById('nav-filter-more')?.addEventListener('click', () => {
            UserFiltersGeneral.moreFiltersClickEvent();
        });

        document.getElementById('nav-filter-more')?.addEventListener('keyup', () => {
            UserFiltersGeneral.moreFiltersClickEvent();
        });

        document.getElementById("user-filters-balances-debit")?.addEventListener("click", (event: MouseEvent) => {
            UserFiltersMoreFiltersBalances.clickEvent(event, 'debit');
        });
        document.getElementById("user-filters-balances-debit")?.addEventListener("keyup", (event: KeyboardEvent) => {
            if (event instanceof KeyboardEvent && (event.key === 'Space' || event.key === ' ')) {
                stopPropPrevDefault(event);
                UserFiltersMoreFiltersBalances.clickEvent(event, 'debit');
            }
        });
        document.getElementById("user-filters-balances-credit")?.addEventListener("click", (event: MouseEvent) => {
            UserFiltersMoreFiltersBalances.clickEvent(event, 'credit');
        });
        document.getElementById("user-filters-balances-credit")?.addEventListener("keyup", (event: KeyboardEvent) => {
            if (event instanceof KeyboardEvent && (event.key === 'Space' || event.key === ' ')) {
                stopPropPrevDefault(event);
                UserFiltersMoreFiltersBalances.clickEvent(event, 'credit');
            }
        });
        

        // Array includes: form-information-instance, form-information-zip, form-information-zip, form-information-help, form-information-html
        const links = [...document.querySelectorAll(`a[id*="form-information-"]`)];
        links.forEach(link => {
            link.addEventListener('keyup', (event) => {
                if (event instanceof KeyboardEvent && (event.key === 'Enter' || event.key === 'Space' || event.key === ' ')) {
                    const id= link.getAttribute('id');
                    document.getElementById(id as string)?.click();
                }
            });
        });
        //#facts-menu-button          
        document.getElementById('facts-menu-button')?.addEventListener("keyup", (event: KeyboardEvent) => {
            if (event instanceof KeyboardEvent && (event.key === 'Enter' || event.key === 'Space' || event.key === ' ')){
                event.preventDefault();
                document.getElementById('facts-menu-button')?.click();
            }
        });  

        document.getElementById("current-filters-reset-all")?.addEventListener("click", () => {
            UserFiltersDropdown.resetAll();
        });
        document.getElementById("current-filters-reset-all")?.addEventListener("keyup", (event: KeyboardEvent) => {
            if (!actionKeyHandler(event)) return;
            UserFiltersDropdown.resetAll();
        });

        document.getElementById("fact-menu-secondary-toggle")?.addEventListener("click", (event: MouseEvent) => {
            FactsMenu.toggle(event);
        });
        document.getElementById("fact-menu-secondary-toggle")?.addEventListener("keyup", (event: KeyboardEvent) => {
            if (!actionKeyHandler(event)) return;
            FactsMenu.toggle(event);
        });

        document.getElementById('nav-filter-dropdown')?.addEventListener('change', (event) => {
            UserFiltersDataRadios.clickEvent(event);
        });
        document.getElementById('nav-filter-tags-dropdown')?.addEventListener('change', (event) => {
            UserFiltersTagsRadios.clickEvent(event);
        });

        // when clicking outside of search suggestions, make sure suggestions div disappears
        // Need to handle doc, inline facts, and fact list elems, as the latter click events aren't propagating to doc.
        document?.addEventListener('click', (event) => {
            if (event.target?.id !== "global-search") {
                ConstantsFunctions.emptyHTMLByID('suggestions');
            }
        })

        document.getElementById('sections-menu-search-submit')?.addEventListener('submit', (event) => {
            event.preventDefault();
            SectionsSearch.submit();
            return false;
        });

        document.getElementById('section-menu-search-btn-clear')?.addEventListener('click', () => {
            SectionsSearch.clear();
        });
        document.getElementById('section-menu-search-btn-clear')?.addEventListener('keyup', (event: KeyboardEvent) => {
            if (!actionKeyHandler(event)) return;
            SectionsSearch.clear();
        });


        // global search
        document.getElementById('global-search-form')?.addEventListener('submit', (event) => {
            event.preventDefault();
            let valueToSearchFor = (document.getElementById('global-search') as HTMLInputElement).value;
            if (valueToSearchFor.length > 1) {
                Search.submit();
            } else {
                Search.clear();
            }
        });

        let globalSearchTimeout: string | number | NodeJS.Timeout | null | undefined = null;
        document.getElementById('global-search')?.addEventListener('keyup', () => {
            if (globalSearchTimeout) {
                clearTimeout(globalSearchTimeout);
            }
            globalSearchTimeout = setTimeout(() => {
                Search.suggestions();
            }, 500)
        });

        document.getElementById('search-btn-clear')?.addEventListener("click", () => {
            Search.clear();
        });
        document.getElementById('search-btn-clear')?.addEventListener("keyup", (event) => {
            if (event.key === 'Enter' || event.key === 'Space' || event.key === ' ') {
                Search.clear();
            }
        });
        
        const searchOptions = document.querySelectorAll('input[name="search-options"], #searchOptionsContainer label');
        searchOptions.forEach(opt => {
            opt.addEventListener('keyup', (event) => {
                const keyEvent = <KeyboardEvent> event;
                if (keyEvent.key == 'Space' || keyEvent.key == ' ') {
                    let search = document.getElementById('global-search') as HTMLInputElement;
                    let searchText = search?.value;
                    if (searchText?.length) {
                        Search.submit();
                    }
                }
                // prevent drop down from closing on action
                event.stopPropagation();
                (opt as HTMLElement).focus()
            });
            opt.addEventListener('click', (event) => {
                const search = document.getElementById('global-search') as HTMLInputElement;
                const searchText = search?.value;
                if (searchText?.length) {
                    Search.submit();
                }
                // prevent drop down from closing on action
                event.stopPropagation();
                (opt as HTMLElement).focus()
            });
        })

        // Custom handler to allow up down arrow keys to navigate search options
        const searchCheckboxes = document.querySelectorAll('#global-search-options, input[name="search-options"]');
        searchCheckboxes.forEach((checkbox, index) => {
            checkbox.addEventListener('keyup', (event) => {
                const keyEvent = <KeyboardEvent> event;
                if (keyEvent.key == 'ArrowUp') {
                    if (index === 0) {
                        (searchCheckboxes[searchCheckboxes.length - 1] as HTMLElement)?.focus();
                    } else {
                        (searchCheckboxes[index - 1] as HTMLElement).focus();
                    }
                }
                if (keyEvent.key == 'ArrowDown') {
                    if (index === searchCheckboxes.length - 1) {
                        (searchCheckboxes[0] as HTMLElement).focus();
                    } else {
                        (searchCheckboxes[index + 1] as HTMLElement).focus();
                    }
                }
            });
        })

        const dataFilterNav = document.getElementById("nav-filter-data") as HTMLInputElement;
        dataFilterNav?.addEventListener('keyup', () => {
            ConstantsFunctions.emptyHTMLByID('suggestions');
        });

        document.getElementById('hover-option-select')?.addEventListener("change", (event: Event) => {
            ModalsSettings.hoverOption(event);
        });

        document.getElementById('scroll-position-select')?.addEventListener("change", (event: Event) => {
            if (!PRODUCTION) console.log('scroll-position-select')
            ModalsSettings.scrollPosition(event);
        });

        document.getElementById('fact-copy-content-close')?.addEventListener('click', (event: MouseEvent) => {
            Modals.copyContent(event, 'fact-modal-carousel', 'fact-copy-content');
        });

        document.getElementById('fact-copy-content-close')?.addEventListener('keyup', (event: KeyboardEvent) => {
            Modals.copyContent(event, 'fact-modal-carousel', 'fact-copy-content');
        });

        document.getElementById('fact-nested-copy-content')?.addEventListener('click', (event: MouseEvent) => {
            Modals.copyContent(event, 'modal-fact-nested-content-carousel', 'fact-nested-copy-paste');
        });

        document.getElementById('fact-nested-copy-content')?.addEventListener('keyup', (event: KeyboardEvent) => {
            Modals.copyContent(event, 'modal-fact-nested-content-carousel', 'fact-nested-copy-paste');
        });
        // scroll-position-select
        // scrollPosition

        const closeOtherSideBars = (barToOpenId: string) => {
            const sidebars = document.getElementsByClassName('sidebar');
            for (const elem in sidebars) {
                const sidebarElem = sidebars[elem]
                if (sidebarElem?.id?.length && sidebarElem?.id != barToOpenId) {
                    if (sidebarElem.classList) {
                        sidebarElem?.classList?.remove('show')
                    }
                }
            }
        }

        // help menu
        const helpMenu = document.getElementById('help-menu');
        helpMenu?.addEventListener('show.bs.collapse', (event: Event) => {
            closeOtherSideBars(event!.target!.id)
        })
        
        // help sidebar section - prevent propagation
        const helpSidebarCollapsableSections = document.querySelectorAll('#help-sections .collapse');
        helpSidebarCollapsableSections?.forEach(helpSection => {
            helpSection?.addEventListener('show.bs.collapse', (event: Event) => {
                event.stopPropagation(); // so that the sidebar doesn't close
            })
        })

        // #facts-menu-button
        const factsMenu = document.getElementById('facts-menu');
        factsMenu?.addEventListener('show.bs.collapse', () => {
            // FactsMenu.toggle(event as MouseEvent | KeyboardEvent); // not needed
            closeOtherSideBars('facts-menu');
            FactsMenu.prepareForPagination();
        })
        //#facts-menu-button
        document.getElementById('facts-menu-button')?.addEventListener("keyup", (event: KeyboardEvent) => {
            if (event instanceof KeyboardEvent && (event.key === 'Enter' || event.key === 'Space' || event.key === ' ')) {
                document.getElementById('facts-menu-button')?.click();
            }
        });
        // #sections-dropdown-link
        const sectionsSidebar = document.getElementById('sections-menu');
        sectionsSidebar?.addEventListener('show.bs.collapse', () => {
            // FactsMenu.toggle(event as MouseEvent | KeyboardEvent); // not needed
            closeOtherSideBars('sections-menu')
        })

        // fact-table
        const factTableMenu = document.getElementById('fact-table-container');
        factTableMenu?.addEventListener('shown.bs.offcanvas', () => FactsTable.toggle(true));
        factTableMenu?.addEventListener('hidden.bs.offcanvas', () => FactsTable.toggle(false));

        // facts-breakdown-button
        const factsBreakdownMenu = document.getElementById('facts-breakdown-container');
        factsBreakdownMenu?.addEventListener('shown.bs.offcanvas', () => FactsChart.toggle(true));
        factsBreakdownMenu?.addEventListener('hidden.bs.offcanvas', () => FactsChart.toggle(false));
    }
}

export const addVArrowNav = (navigableElems: NodeListOf<Element>) => {
    navigableElems.forEach((elem, index) => {
        elem.addEventListener('keyup', (event) => {
            const keyEvent = <KeyboardEvent> event;
            if (keyEvent.key == 'ArrowUp') {
                if (index === 0) {
                    (navigableElems[navigableElems.length - 1] as HTMLElement)?.focus();
                } else {
                    (navigableElems[index - 1] as HTMLElement).focus();
                }
            }
            if (keyEvent.key == 'ArrowDown') {
                if (index === navigableElems.length - 1) {
                    (navigableElems[0] as HTMLElement).focus();
                } else {
                    (navigableElems[index + 1] as HTMLElement).focus();
                }
            }
        });
    })
}
