'use strict';

var mobx = require('mobx');

class BaseSyncElement extends HTMLElement {
    constructor() {
        super();
        this.disposers = [];
        this.value = null;
        this.connectionStatus = {
            type: 'offline',
            connected: false,
            peers: 0,
        };
        this.presence = {
            users: new Map(),
            localClientId: null,
            activeCount: 0,
        };
        this.shadow = this.attachShadow({ mode: 'open' });
    }
    connectedCallback() {
        this.model = this.createModel();
        this.setupObservers();
        this.render();
        this.onConnected();
    }
    disconnectedCallback() {
        this.disposers.forEach(dispose => dispose());
        this.disposers = [];
        if (this.model) {
            this.model.destroy();
        }
        this.onDisconnected();
    }
    setupObservers() {
        const valueDisposer = mobx.autorun(() => {
            this.value = this.model.getValue();
            this.onValueChanged(this.value);
            this.render();
        });
        this.disposers.push(valueDisposer);
        const connectionDisposer = mobx.autorun(() => {
            this.connectionStatus = this.model.connectionStatus;
            this.onConnectionChanged(this.connectionStatus);
            this.render();
        });
        this.disposers.push(connectionDisposer);
        const presenceDisposer = mobx.autorun(() => {
            this.presence = this.model.presenceInfo;
            this.onPresenceChanged(this.presence);
            this.render();
        });
        this.disposers.push(presenceDisposer);
    }
    onConnected() {
    }
    onDisconnected() {
    }
    onValueChanged(value) {
    }
    onConnectionChanged(status) {
    }
    onPresenceChanged(presence) {
    }
    setValue(value) {
        this.model.setValue(value);
    }
    getValue() {
        return this.model.getValue();
    }
    get isSyncConnected() {
        return this.connectionStatus.connected;
    }
    get activeUsers() {
        return this.presence.activeCount;
    }
    get connectionType() {
        return this.connectionStatus.type;
    }
    html(strings, ...values) {
        return strings.reduce((result, str, i) => {
            const value = values[i - 1];
            return result + (value !== undefined ? value : '') + str;
        });
    }
    addStyles(css) {
        const style = document.createElement('style');
        style.textContent = css;
        this.shadow.appendChild(style);
    }
    $(selector) {
        return this.shadow.querySelector(selector);
    }
    $$(selector) {
        return this.shadow.querySelectorAll(selector);
    }
    on(selector, event, handler) {
        const element = this.$(selector);
        if (element) {
            element.addEventListener(event, handler);
        }
    }
    emit(eventName, detail) {
        this.dispatchEvent(new CustomEvent(eventName, {
            detail,
            bubbles: true,
            composed: true,
        }));
    }
}
function customElement(tagName) {
    return function (constructor) {
        if (!customElements.get(tagName)) {
            customElements.define(tagName, constructor);
        }
    };
}
function createSyncElement(tagName, ModelClass, config) {
    class SyncElement extends BaseSyncElement {
        createModel() {
            return new ModelClass({
                room: config.room || this.getAttribute('room') || 'default-room',
                initialValue: config.initialValue,
                debug: config.debug || this.hasAttribute('debug'),
                provider: config.room || this.getAttribute('room')
                    ? {
                        room: config.room || this.getAttribute('room') || 'default-room',
                        ydoc: this.model?.ydoc,
                        webrtc: config.webrtc,
                        websocket: config.websocket,
                        awareness: config.awareness,
                        debug: config.debug,
                        autoConnect: true,
                    }
                    : false,
            });
        }
        render() {
            if (config.styles && !this.$('style')) {
                this.addStyles(config.styles);
            }
            const html = config.template(this.value, this);
            const container = this.$('#content');
            if (container) {
                container.innerHTML = html;
            }
            else {
                this.shadow.innerHTML = `
          ${config.styles ? `<style>${config.styles}</style>` : ''}
          <div id="content">${html}</div>
        `;
            }
        }
    }
    if (!customElements.get(tagName)) {
        customElements.define(tagName, SyncElement);
    }
    return SyncElement;
}

exports.BaseSyncElement = BaseSyncElement;
exports.createSyncElement = createSyncElement;
exports.customElement = customElement;
