import { Service } from '../core/Service.js';
import { CurrentOrganizationKey } from '../lib/StoreKeys.js';
import services from './api_service.js';
var State;
(function (State) {
    State[State["NotChecked"] = 0] = "NotChecked";
    State[State["Checking"] = 1] = "Checking";
    State[State["Checked"] = 2] = "Checked";
})(State || (State = {}));
export var CompletionState;
(function (CompletionState) {
    /**
     * The user has at least one organization and the current organization is selected.
     */
    CompletionState[CompletionState["OK"] = 0] = "OK";
    /**
     * The user has at leas two organizations and no valid selection.
     */
    CompletionState[CompletionState["NotSelected"] = 1] = "NotSelected";
    /**
     * The user have no organizations. Setup is needed.
     */
    CompletionState[CompletionState["NoOrganizations"] = 2] = "NoOrganizations";
    /**
     * Unable to determine the state due to an error.
     */
    CompletionState[CompletionState["Error"] = 3] = "Error";
})(CompletionState || (CompletionState = {}));
const OrgsCacheKey = 'user_organizations';
export default class OrganizationService extends Service {
    static key = 'api-service/organization';
    state = State.NotChecked;
    organizations = [];
    organizationId;
    /**
     * A pending organization ID that was set via the URL query parameter `oid`.
     * When it is set, it preselects the organization when loading list of organizations.
     * This will override the `organizationId` set in the local storage.
     */
    pendingOid;
    /**
     * A hidden value for the `updateComplete` getter.
     */
    #updateComplete;
    /**
     * The resolver to call when the update completes.
     */
    #updateResolver;
    async onCreate() {
        const url = new URL(window.location.href);
        this.pendingOid = url.searchParams.get('oid');
    }
    async getUserOrganization(id) {
        await this.#updateComplete;
        const org = this.organizations.find((i) => i.key === id);
        if (!org) {
            throw new Error(`Organization with id ${id} not found`);
        }
        return org;
    }
    async currentOrganization() {
        if (this.state === State.Checking) {
            await this.#updateComplete;
        }
        if (!this.organizationId) {
            return undefined;
        }
        // TODO: we will store the orgs list in the local/session store
        // so we won't be pinging server with every page reload.
        return this.organizations.find((i) => i.key === this.organizationId);
    }
    async hasGrantType(grantType) {
        const org = await this.currentOrganization();
        if (!org) {
            return false;
        }
        return org.grantType === grantType;
    }
    async hasRoles(types) {
        const org = await this.currentOrganization();
        if (!org) {
            return false;
        }
        return types.includes(org.grantType);
    }
    /**
     * Checks if the user is the owner of the current organization.
     * @returns `true` if the user is the owner of the current organization, `false` otherwise.
     */
    async isOwner() {
        return this.hasGrantType('owner');
    }
    /**
     * Checks if the user is a manager of the current organization.
     * @returns `true` if the user is a manager of the current organization, `false` otherwise.
     */
    async isManager() {
        return this.hasGrantType('manager');
    }
    /**
     * Checks if the user is an editor of the current organization.
     * @returns `true` if the user is a editor of the current organization, `false` otherwise.
     */
    async isEditor() {
        return this.hasGrantType('editor');
    }
    /**
     * Forces to get the list of organizations from the server.
     *
     * Returns one of the following states:
     *
     * - `CompletionState.OK` - The user has at least one organization and the current organization is selected.
     * - `CompletionState.NotSelected` - The user has at leas two organizations and no valid selection.
     * - `CompletionState.NoOrganizations` - The user have no organizations. Setup is needed.
     * - `CompletionState.Error` - Unable to determine the state due to an error.
     *
     * @returns The state of the organization creation.
     */
    revalidate() {
        if (this.state === State.Checking) {
            return this.#updateComplete;
        }
        if (this.organizationId) {
            return Promise.resolve(CompletionState.OK);
        }
        this.state = State.Checking;
        this.#updateComplete = new Promise((resolver) => {
            this.#updateResolver = resolver;
        });
        this.#getState();
        return this.#updateComplete;
    }
    /**
     * Reads the list of organizations either from the cache or from the server.
     */
    async #getState() {
        const loaded = await this.#loadCache();
        if (!loaded) {
            try {
                await this.#callOrganizations();
            }
            catch {
                this.#resolve(CompletionState.Error);
                this.state = State.Checked;
                return;
            }
        }
        const result = await this.#readState();
        this.state = State.Checked;
        this.#resolve(result);
    }
    async #loadCache() {
        const cache = await services.get('cache');
        const orgs = await cache.get(OrgsCacheKey);
        if (orgs) {
            this.organizations = orgs;
            return true;
        }
        return false;
    }
    async #saveCache(orgs) {
        const cache = await services.get('cache');
        if (orgs.length === 0) {
            await cache.delete(OrgsCacheKey);
        }
        else {
            await cache.set(OrgsCacheKey, orgs, cache.TTL.OneHour);
        }
    }
    async #callOrganizations() {
        const sdk = await services.get('sdk');
        const orgs = await sdk.organizations.list();
        this.organizations = orgs.items || [];
        await this.#saveCache(orgs.items);
    }
    #resolve(state) {
        if (this.#updateResolver) {
            this.#updateResolver(state);
            this.#updateResolver = undefined;
        }
    }
    async #readState() {
        const config = await services.get('config');
        const selected = this.pendingOid ?? (await config.local.get(CurrentOrganizationKey));
        this.pendingOid = undefined; // Clear the pending OID after reading it
        const hasSelected = this.organizations.some((i) => i.key === selected);
        let result;
        if (selected && hasSelected) {
            this.organizationId = selected;
            result = CompletionState.OK;
            await config.local.set(CurrentOrganizationKey, selected);
        }
        else if (this.organizations.length === 1) {
            const key = this.organizations[0].key;
            await config.local.set(CurrentOrganizationKey, key);
            this.organizationId = key;
            result = CompletionState.OK;
        }
        else if (this.organizations.length) {
            result = CompletionState.NotSelected;
        }
        else {
            result = CompletionState.NoOrganizations;
        }
        return result;
    }
    /**
     * When the user has no organizations, it set the organization as the only one
     * and persists the organization id as the selected organization.
     * @param org The organization to add.
     */
    async setupUserOrganization(org) {
        const hasOrg = this.organizations.some((i) => i.key === org.key);
        if (!hasOrg) {
            this.organizations.push(org);
        }
        const config = await services.get('config');
        await config.local.set(CurrentOrganizationKey, org.key);
        this.organizationId = org.key;
    }
}
//# sourceMappingURL=OrganizationService.js.map