import { isDevEnvironment } from "../debug/index.js";
import { iconFontUrl, loadFont } from "./fonts.js";
import { WebXRButtonFactory } from "./WebXRButtons.js";

declare global {
    interface HTMLElementTagNameMap {
        "needle-button": NeedleButtonElement;
    }
}

const htmlTagName = "needle-button";
const isDev = isDevEnvironment();

/**
 * A <needle-button> can be used to simply add VR, AR or Quicklook buttons to your website without having to write any code.  
 * @example
 * ```html
 * <needle-button ar></needle-button>
 * <needle-button vr></needle-button>
 * <needle-button quicklook></needle-button>
 * ```
 * 
 * @example custom label
 * ```html
 * <needle-button ar>Start AR</needle-button>
 * <needle-button vr>Start VR</needle-button>
 * <needle-button quicklook>View in AR</needle-button>
 * ```
 * 
 * @example custom styling
 * ```html
 * <!-- You can either style the element directly or use a CSS stylesheet -->
 * <style>
 * needle-button {
 *    background-color: red;
 *   color: white;
 * }
 * </style>
 * <needle-button ar>Start AR</needle-button>
 * ```
 */
export class NeedleButtonElement extends HTMLElement {

    static observedAttributes = ["ar", "vr", "quicklook"];

    constructor() {
        super();
        this.removeEventListener("click", this.#onclick);
        this.addEventListener("click", this.#onclick);
    }

    attributeChangedCallback(_name: string, _oldValue: string, _newValue: string) {
        this.#update()
    }

    #root!: ShadowRoot;
    #slot!: HTMLSlotElement;
    /** These are the default styles that can be overridden by the user from the outside by styling <needle-button> */
    #styles!: HTMLStyleElement;

    /** This is the button that was generated using one of the factories */
    #button: HTMLButtonElement | undefined;
    /** If AR or VR is requested we create and use the webxr button factory to create a button with default behaviour */
    #webxrfactory: WebXRButtonFactory | undefined;

    #observer: MutationObserver | undefined;

    #update() {
        this.#button?.remove();


        if (this.getAttribute("ar") != null) {
            this.#webxrfactory ??= new WebXRButtonFactory()
            this.#button = this.#webxrfactory.createARButton();
        }
        else if (this.getAttribute("vr") != null) {
            this.#webxrfactory ??= new WebXRButtonFactory()
            this.#button = this.#webxrfactory.createVRButton();
        }
        else if (this.getAttribute("quicklook") != null) {
            this.#webxrfactory ??= new WebXRButtonFactory()
            this.#button = this.#webxrfactory.createQuicklookButton();
        }
        else {
            if (isDev) {
                console.warn("No button type specified for <needle-button>. Use either ar, vr or quicklook attribute.")
            }
            else {
                console.debug("No button type specified for <needle-button>. Use either ar, vr or quicklook attribute.")
            }
            return;
        }

        this.#root ??= this.attachShadow({ mode: "open" });
        this.#slot ??= document.createElement("slot");
        this.#styles ??= document.createElement("style");
        this.#styles.innerHTML = `
            button {
                all: initial;
                cursor: inherit;
                color: inherit;
                font-family: inherit;
                gap: inherit;
                white-space: nowrap;
            }
        `;
        const hasUnstyledAttribute = this.getAttribute("unstyled") != undefined;
        if (!hasUnstyledAttribute) {
            this.#styles.innerHTML += `
            :host {
                display: inline-block;
                background: rgba(255, 255, 255, .8);
                backdrop-filter: blur(10px);
                width: fit-content;
                transition: background .2s;

                cursor: pointer;
                padding: 0.4rem .5rem;
                border-radius: 0.8rem;
                color: black;
                background: rgba(245, 245, 245, .8);
                outline: rgba(0,0,0,.05) 1px solid;
            }
            :host(:hover) {
                background: rgba(255, 255, 255, 1);
                transition: background .2s;
            }
            slot {
                display: flex;
                align-items: center;
                justify-content: center;
                gap: .5rem;
            }
`
        }

        /**
         * We now structure the results as follows:
         * <button>
         *  <slot>
         *      <original_button_content>
         *  </slot>
         * </button> 
         */
        this.#slot.innerHTML = this.#button.innerHTML;
        this.#slot.style.cssText = `display: flex; align-items: center; justify-content: center;`
        this.#button.innerHTML = this.#slot.outerHTML;
        this.#root.innerHTML = this.#button.outerHTML;
        this.#root.prepend(this.#styles);
        loadFont(iconFontUrl, { element: this.#root });

        this.#observer?.disconnect();
        this.#observer ??= new MutationObserver(() => this.#updateVisibility());
        this.#observer.observe(this.#button, { attributes: true });
        if(isDev) {
            console.log("Needle Button updated")
        }
    }

    #updateVisibility() {
        if (this.#button) {
            if (this.#button.style.display === "none") {
                this.style.display = "none";
            }
            else if (this.style.display === "none") {
                this.style.display = "";
            }
        }
    }

    #onclick = (_ev: MouseEvent) => {
        if (isDev) {
            console.log("Needle Button clicked")
        }
        if (_ev.defaultPrevented) return;

        if (this.#button) {
            this.#button.click()
        }

    }

}



if (typeof window !== "undefined" && !window.customElements.get(htmlTagName))
    window.customElements.define(htmlTagName, NeedleButtonElement);