'use strict';

const listener = require('./listener-154f256a.js');
const browser = require('./browser-9ac97263.js');
const helpers = require('./helpers-298b0de9.js');

class BalFocusListener extends listener.ListenerAbstract {
    constructor() {
        super(...arguments);
        this.onFocusin = (ev) => {
            this.notify({ ev, isFocusIn: true, isFocusOut: false });
        };
        this.onFocusout = async (ev) => {
            await helpers.waitAfterIdleCallback();
            if (browser.balBrowser.hasDocument && this.el) {
                const target = document.activeElement;
                if (target && !helpers.isDescendant(this.el, target)) {
                    this.notify({ ev, isFocusIn: false, isFocusOut: true });
                }
            }
        };
    }
    connect(el) {
        super.connect(el);
        if (this.el) {
            helpers.addEventListener(this.el, 'focusin', this.onFocusin);
            helpers.addEventListener(this.el, 'focusout', this.onFocusout);
        }
    }
    disconnect() {
        super.disconnect();
        if (this.el) {
            helpers.removeEventListener(this.el, 'focusin', this.onFocusin);
            helpers.removeEventListener(this.el, 'focusout', this.onFocusout);
        }
    }
}

class BalFocusSubject extends listener.SingleSubject {
    constructor() {
        super((observer, data) => {
            if (data) {
                if (data.isFocusIn) {
                    if (observer.hasFocus === false) {
                        observer.focusInListener(data.ev);
                    }
                    observer.hasFocus = true;
                }
                if (data.isFocusOut) {
                    observer.focusOutListener(data.ev);
                    observer.hasFocus = false;
                }
            }
        });
        this.listener = new BalFocusListener();
    }
    attach(observer) {
        super.attach(observer);
        this.listener.connect(observer.el);
        this.listener.add(info => super.notify(info));
    }
    detach() {
        super.detach();
        this.listener.disconnect();
    }
}

function ListenToFocus() {
    return function (target, _propertyKey, _descriptor) {
        const { connectedCallback, disconnectedCallback } = target;
        target.connectedCallback = function () {
            if (!this._balFocusSubject) {
                this._balFocusSubject = new BalFocusSubject();
                this._balFocusSubject.attach(this);
            }
            return connectedCallback && connectedCallback.call(this);
        };
        target.disconnectedCallback = function () {
            if (this._balFocusSubject) {
                this._balFocusSubject.detach();
                this._balFocusSubject = undefined;
            }
            return disconnectedCallback && disconnectedCallback.call(this);
        };
    };
}

exports.ListenToFocus = ListenToFocus;
