import { querySelectorAllDeep } from 'query-selector-shadow-dom';
import Action from "./Action";

export default abstract class Rule {

    event: string;
    css: string;
    xpath: string;
    prefix: string;
    suffix: string;
    key: string;
    code: string;
    contextURL: string;
    contextCSS: string;
    contextXPath: string;
    description: string;
    strategy;

    constructor(prefix: string, suffix: string, event: string, css: string, xpath: string,
        code: string, key: string, contextURL: string, contextCSS: string, contextXPath: string, description: string) {

        this.event = event;
        this.code = code;
        this.css = css;
        this.xpath = xpath;
        this.prefix = prefix;
        this.suffix = suffix;
        this.key = key;
        this.contextURL = contextURL;
        this.contextCSS = contextCSS;
        this.contextXPath = contextXPath;
        this.description = description;
    }

    match(event) : boolean {
        if (event.type !== this.event) {
            return false;
        }

        if (this.event === "keyup" || this.event === "keydown" || this.event === "keypress") {
            if (this.code && event.code !== this.code) {
                return false
            }
            if (this.key && event.key !== this.key) {
                return false
            }
        }
        return true;
    }


    abstract makeAction(event): Action;

    abstract actionToElements(action: Action): Element[] ;

    findActionMappedTarget(event: Event): HTMLElement {
        const target = event.composedPath()[0];
        if (target instanceof Element) {
            const element = target as HTMLElement;
            if (element.hasAttribute("aifex_style")) {
                return element;
            } else {
                return element.closest("[aifex_style]")
            }
        } else {
            return null;
        }
    }

    findMatchedElements() : HTMLElement[]{
        let context;

        if (this.contextXPath) {
            try {
                const result = document.evaluate(this.xpath, document, null, XPathResult.ANY_TYPE, null);
                context = result.iterateNext();
            } catch (e) {
                console.error(e);
            }
            if (!context) {
                return [];
            }
        }
        if (this.contextCSS) {
            context = document.querySelector(this.contextCSS);
            if (!context) {
                return [];
            }
        }

        let elements = [];
        if (this.xpath) {
            try {
                let result;
                if (context) {
                    result = document.evaluate(this.xpath, context, null, XPathResult.ANY_TYPE, null);
                } else {
                    result = document.evaluate(this.xpath, document, null, XPathResult.ANY_TYPE, null);
                }
                let node = result.iterateNext();
                while (node) {
                    elements.push(node);
                    node = result.iterateNext();
                }
            } catch (e) {
                console.error(e);
            }
        } else {
            if (context) {
                elements = querySelectorAllDeep(this.css, context)
            } else {
                elements = querySelectorAllDeep(this.css)
            }
        }
        return elements;
    }

}