// retoor <retoor@molodetz.nl>

import { Component } from "./Component.js";

export class AppDialog extends Component {
    connectedCallback() {
        if (this._built) {
            return;
        }
        this._built = true;
        this.resolver = null;
        this.mode = "confirm";
        this.lastFocus = null;
        this.build();
    }

    build() {
        const overlay = document.createElement("div");
        overlay.className = "dialog-overlay";
        overlay.setAttribute("role", "dialog");
        overlay.setAttribute("aria-modal", "true");
        overlay.innerHTML =
            '<div class="card dialog-card">' +
            '<div class="modal-header"><h3 class="dialog-title"></h3>' +
            '<button type="button" class="modal-close btn-ghost btn-icon dialog-close">&times;</button></div>' +
            '<p class="dialog-message"></p>' +
            '<ul class="dialog-links" hidden></ul>' +
            '<div class="dialog-field" hidden><label class="dialog-field-label"></label>' +
            '<input type="text" class="dialog-input" autocomplete="off"></div>' +
            '<div class="modal-footer">' +
            '<button type="button" class="btn btn-secondary dialog-cancel">Cancel</button>' +
            '<button type="button" class="btn btn-primary dialog-confirm">OK</button>' +
            "</div></div>";
        this.appendChild(overlay);

        this.overlay = overlay;
        this.titleEl = overlay.querySelector(".dialog-title");
        this.messageEl = overlay.querySelector(".dialog-message");
        const uid = Math.random().toString(36).slice(2, 9);
        this.titleEl.id = `dialog-title-${uid}`;
        this.messageEl.id = `dialog-message-${uid}`;
        overlay.setAttribute("aria-labelledby", this.titleEl.id);
        overlay.setAttribute("aria-describedby", this.messageEl.id);
        this.links = overlay.querySelector(".dialog-links");
        this.field = overlay.querySelector(".dialog-field");
        this.fieldLabel = overlay.querySelector(".dialog-field-label");
        this.input = overlay.querySelector(".dialog-input");
        this.cancelBtn = overlay.querySelector(".dialog-cancel");
        this.confirmBtn = overlay.querySelector(".dialog-confirm");

        overlay.addEventListener("click", (e) => {
            if (e.target === overlay) this.dismiss();
        });
        overlay.querySelector(".dialog-close").addEventListener("click", () => this.dismiss());
        this.cancelBtn.addEventListener("click", () => this.dismiss());
        this.confirmBtn.addEventListener("click", () => this.accept());
        this.input.addEventListener("keydown", (e) => {
            if (e.key === "Enter") {
                e.preventDefault();
                this.accept();
            }
        });
        document.addEventListener("keydown", (e) => {
            if (e.key === "Escape" && this.overlay.classList.contains("visible")) {
                e.preventDefault();
                this.dismiss();
            }
        });
        overlay.addEventListener("keydown", (e) => {
            if (e.key !== "Tab") return;
            const items = [
                ...overlay.querySelectorAll(
                    'a[href], button:not([disabled]), input:not([disabled]), select, textarea, [tabindex]:not([tabindex="-1"])'
                ),
            ].filter((el) => el.offsetParent !== null);
            if (!items.length) return;
            const first = items[0];
            const last = items[items.length - 1];
            if (e.shiftKey && document.activeElement === first) {
                e.preventDefault();
                last.focus();
            } else if (!e.shiftKey && document.activeElement === last) {
                e.preventDefault();
                first.focus();
            }
        });
    }

    get isOpen() {
        return this.overlay.classList.contains("visible");
    }

    open(mode, options) {
        const opts = options || {};
        this.mode = mode;
        this.titleEl.textContent = opts.title || (mode === "prompt" ? "Rename" : mode === "alert" ? "Notice" : "Confirm");
        this.messageEl.textContent = opts.message || "";
        this.messageEl.hidden = !opts.message;
        this.confirmBtn.textContent = opts.confirmLabel || (mode === "alert" ? "OK" : mode === "prompt" ? "Save" : "Confirm");
        this.cancelBtn.textContent = opts.cancelLabel || "Cancel";
        this.cancelBtn.style.display = mode === "alert" ? "none" : "";
        this.confirmBtn.classList.toggle("dialog-danger", !!opts.danger);
        this.renderLinks(opts.links);

        if (mode === "prompt") {
            this.field.hidden = false;
            this.fieldLabel.textContent = opts.label || "";
            this.fieldLabel.hidden = !opts.label;
            this.input.value = opts.value || "";
            this.input.placeholder = opts.placeholder || "";
        } else {
            this.field.hidden = true;
        }

        this.lastFocus = document.activeElement;
        this.overlay.classList.add("visible");
        const focusTarget = mode === "prompt" ? this.input : this.confirmBtn;
        setTimeout(() => {
            focusTarget.focus();
            if (mode === "prompt") this.input.select();
        }, 20);

        return new Promise((resolve) => { this.resolver = resolve; });
    }

    renderLinks(links) {
        const items = Array.isArray(links) ? links : [];
        this.links.replaceChildren();
        this.links.hidden = !items.length;
        for (const item of items) {
            const anchor = document.createElement("a");
            anchor.href = item.href;
            anchor.textContent = item.label;
            anchor.target = "_blank";
            anchor.rel = "noopener";
            const row = document.createElement("li");
            row.appendChild(anchor);
            this.links.appendChild(row);
        }
    }

    accept() {
        const value = this.mode === "prompt" ? this.input.value : true;
        this.close(value);
    }

    dismiss() {
        this.close(this.mode === "prompt" ? null : this.mode === "alert" ? undefined : false);
    }

    close(value) {
        this.overlay.classList.remove("visible");
        if (this.lastFocus && this.lastFocus.focus) this.lastFocus.focus();
        const resolve = this.resolver;
        this.resolver = null;
        if (resolve) resolve(value);
    }

    confirm(options) {
        return this.open("confirm", options);
    }

    prompt(options) {
        return this.open("prompt", options);
    }

    alert(options) {
        return this.open("alert", options);
    }
}

customElements.define("dp-dialog", AppDialog);
