import { createStore } from "@stencil/store";
import dayjs from "dayjs";
import PubSub from "pubsub-js";
import { i18n, getLocale, } from "./utils/i18n";
const ID_KEY_PREFIX = "ednl-ls-";
const DATA_TOPIC_POSTFIX = "-data";
const SUBS_TOPIC_POSTFIX = "-subs";
function hasIdKey(idKey) {
    return typeof idKey === "string" && idKey.length > 0;
}
const storesContainer = createStore({
    // eslint-disable-next-line stencil/ban-side-effects
    updatedAt: Date.now(),
    stores: new Map(),
});
const withStoreTranslator = (store) => {
    if (store === undefined) {
        throw new Error("Store is unavailable");
    }
    const localeStore = store;
    if (typeof localeStore.t !== "function") {
        localeStore.t = (key, options) => {
            const locale = getLocale(localeStore.state.locale);
            return i18n.t(key, options === undefined ? { lng: locale } : Object.assign(Object.assign({}, options), { lng: locale }));
        };
    }
    return localeStore;
};
export function createNewStore(idKey, initialState) {
    // Gather initial state, use defaults if not provided
    const newStore = withStoreTranslator(createStore({
        historicalSensorData: (initialState === null || initialState === void 0 ? void 0 : initialState.historicalSensorData) || [],
        currentSensorData: (initialState === null || initialState === void 0 ? void 0 : initialState.currentSensorData) || {
            lastUpdate: 0,
            values: {},
            updated: {},
        },
        datePicker: (initialState === null || initialState === void 0 ? void 0 : initialState.datePicker) || {
            start: dayjs()
                .hour(dayjs().hour())
                .minute(0)
                .second(0)
                .millisecond(0)
                .toISOString(), // Start date/time in ISO 8601 string
            end: dayjs()
                .hour(dayjs().hour() + 1)
                .minute(0)
                .second(0)
                .millisecond(0)
                .toISOString(), // End date/time in ISO 8601 string
        },
        error: (initialState === null || initialState === void 0 ? void 0 : initialState.error) || {
            hasError: false,
            messageKey: undefined,
            type: "",
        },
        hasBackDoor: (initialState === null || initialState === void 0 ? void 0 : initialState.hasBackDoor) || false,
        locale: getLocale(initialState === null || initialState === void 0 ? void 0 : initialState.locale),
    }));
    // Create new store
    storesContainer.state.stores.set(ID_KEY_PREFIX + idKey, newStore);
    // Update updatedAt to notify subscribers
    storesContainer.set("updatedAt", Date.now());
    // Listen for new subscriptions and react by publishing the current state
    PubSub.subscribe(ID_KEY_PREFIX + idKey + SUBS_TOPIC_POSTFIX, () => {
        publishData(idKey);
    });
    // Publish the data for existing subscribers
    publishData(idKey);
}
export async function getStore(idKey) {
    const idKeyWithPrefix = ID_KEY_PREFIX + idKey;
    // We need to return a promise for stencil lifecycle methods to be able to await
    // See: https://stenciljs.com/docs/component-lifecycle#async-lifecycle-methods
    return new Promise((resolve, reject) => {
        // If no idKey is provided, return first store, but only if there is only one store in the container
        // We do this to allow backwards compatibility with the old way of using the web components (where there was only one installation)
        // Multiple stores and no idKey indicates user error
        if (!hasIdKey(idKey) && storesContainer.state.stores.size > 1) {
            reject("Multiple installations detected without using idKey. Add an idKey to each component. See: https://springtree.github.io/ednl-liftstatus-web-components/#/multiple-installations");
            return;
        }
        // If no idKey is provided, return first store
        if (!hasIdKey(idKey) &&
            storesContainer.state.stores.values().next().value !== undefined) {
            resolve(withStoreTranslator(storesContainer.state.stores.values().next().value));
            return;
        }
        // If store exists, return it
        if (hasIdKey(idKey) &&
            storesContainer.state.stores.get(idKeyWithPrefix) !== undefined) {
            resolve(withStoreTranslator(storesContainer.state.stores.get(idKeyWithPrefix)));
            return;
        }
        // If store doesn't exist, wait for it to be created
        storesContainer.onChange("updatedAt", () => {
            // Multiple stores and no idKey indicates user error
            if (!hasIdKey(idKey) && storesContainer.state.stores.size > 1) {
                reject("Multiple installations detected without using idKey. Add an idKey to each component. See: https://springtree.github.io/ednl-liftstatus-web-components/#/multiple-installations");
                return;
            }
            // If no idKey is provided, return first store
            if (!hasIdKey(idKey) &&
                storesContainer.state.stores.values().next().value !== undefined) {
                resolve(withStoreTranslator(storesContainer.state.stores.values().next().value));
                return;
            }
            // If store exists, return it
            if (hasIdKey(idKey) &&
                storesContainer.state.stores.get(idKeyWithPrefix) !== undefined) {
                resolve(withStoreTranslator(storesContainer.state.stores.get(idKeyWithPrefix)));
                return;
            }
        });
    });
}
export async function updateStore(currentSensorData, idKey) {
    const store = await getStore(idKey);
    // Update sensor data
    store.set("currentSensorData", currentSensorData);
    // Update updatedAt to notify subscribers
    storesContainer.set("updatedAt", Date.now());
    // Publish data for external use
    publishData(idKey);
}
export async function updateErrorState(error, idKey) {
    const store = await getStore(idKey);
    store.set("error", error);
    storesContainer.set("updatedAt", Date.now());
    publishData(idKey);
}
export function removeStore(idKey) {
    const idKeyWithPrefix = ID_KEY_PREFIX + idKey;
    // Remove the store from the container
    if (storesContainer.state.stores.has(idKeyWithPrefix)) {
        storesContainer.state.stores.delete(idKeyWithPrefix);
        // Update updatedAt to notify subscribers
        storesContainer.set("updatedAt", Date.now());
        // Clean up PubSub subscriptions for this store
        const subscriptionTopic = ID_KEY_PREFIX + idKey + SUBS_TOPIC_POSTFIX;
        const dataTopic = ID_KEY_PREFIX + idKey + DATA_TOPIC_POSTFIX;
        // Unsubscribe all subscribers for both topics
        PubSub.clearAllSubscriptions(subscriptionTopic);
        PubSub.clearAllSubscriptions(dataTopic);
    }
    else {
        console.warn(`Attempted to remove non-existent store: ${idKey}`);
    }
}
/**
 * This method publishes current state op the store to the data topic.
 * This is used for external applications to subscribe to. Customers can install PubSubJS and subscribe to the data topic.
 * Other components use the store directly.
 */
async function publishData(idKey) {
    const effectiveIdKey = resolveIdKeyForPublish(idKey);
    if (effectiveIdKey === null) {
        return;
    }
    const dataTopic = ID_KEY_PREFIX + effectiveIdKey + DATA_TOPIC_POSTFIX;
    const subscriptionCount = PubSub.countSubscriptions(dataTopic);
    const store = await getStore(effectiveIdKey);
    const state = {
        currentSensorData: store.state.currentSensorData,
        error: store.state.error,
        hasBackDoor: store.state.hasBackDoor,
    };
    // Publish the data for existing subscribers
    if (subscriptionCount > 0) {
        PubSub.publish(dataTopic, state);
    }
}
function resolveIdKeyForPublish(idKey) {
    if (hasIdKey(idKey)) {
        return idKey;
    }
    if (storesContainer.state.stores.size !== 1) {
        return null;
    }
    const firstStoreKey = storesContainer.state.stores.keys().next().value;
    if (typeof firstStoreKey !== "string" || firstStoreKey.length === 0) {
        return null;
    }
    return firstStoreKey.replace(ID_KEY_PREFIX, "");
}
//# sourceMappingURL=store.js.map
