import * as i0 from '@angular/core';
import { InjectionToken, inject, PLATFORM_ID, Injectable, EventEmitter, signal } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { injectSiTranslateService, getBrowserCultureLanguage, getBrowserLanguage } from '@siemens/element-translate-ng/translate';
import { of, ReplaySubject, BehaviorSubject } from 'rxjs';
import { first } from 'rxjs/operators';
import { isRTL } from '@siemens/element-ng/common';

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class SiLocaleStore {
}
const SI_LOCALE_LOCAL_STORAGE_KEY = 'lang';
class SiDefaultLocaleStore extends SiLocaleStore {
    isBrowser;
    constructor(isBrowser) {
        super();
        this.isBrowser = isBrowser;
    }
    get locale() {
        if (this.isBrowser) {
            return localStorage.getItem(SI_LOCALE_LOCAL_STORAGE_KEY) ?? undefined;
        }
        else {
            return undefined;
        }
    }
    saveLocale(locale) {
        if (this.isBrowser) {
            localStorage.setItem(SI_LOCALE_LOCAL_STORAGE_KEY, locale);
            return of(true);
        }
        else {
            return of(false);
        }
    }
}

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
const SI_LOCALE_STORE = new InjectionToken('SI_LOCALE_STORE');
const SI_LOCALE_CONFIG = new InjectionToken('SI_LOCALE_CONFIG');
// this is a function because Angular compiler exports arrows for no good reason
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
function defaultLocaleInitializer(localeId) {
    if (localeId === 'en') {
        return Promise.resolve();
    }
    else {
        return Promise.reject();
    }
}
class SiLocaleService {
    /**
     * Holds the used locale definition like en, de, or en-US.
     */
    locale$;
    /**
     * Emits to indicate that the localization package (e.g. \@angular/common/locales/$\{localeId\})
     * is loaded and registered. Emits after calling `localeInitializer` from the `config` object.
     */
    localePackageLoaded$ = new ReplaySubject(1);
    _nextLocale;
    isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
    translate = injectSiTranslateService();
    localeStore = inject(SiLocaleStore, { optional: true }) ?? new SiDefaultLocaleStore(this.isBrowser);
    /**
     * The config for the local service.
     */
    config = inject(SI_LOCALE_CONFIG, { optional: true }) ?? {
        availableLocales: ['en'],
        defaultLocale: 'en',
        localeInitializer: defaultLocaleInitializer,
        fallbackEnabled: false,
        dynamicLanguageChange: false
    };
    constructor() {
        if (!this.config.defaultLocale) {
            if (this.config.availableLocales && this.config.availableLocales.length > 0) {
                this.config.defaultLocale = this.config.availableLocales[0];
            }
            else {
                this.config.defaultLocale = 'en';
            }
        }
        if (!this.config.availableLocales || this.config.availableLocales.length === 0) {
            this.config.availableLocales = [this.config.defaultLocale];
        }
        // Also adds all locales to the translate service to enable
        // components working with the translate service directly to still work.
        this.translate.availableLanguages = this.config.availableLocales;
        this.config.localeInitializer ??= defaultLocaleInitializer;
        this.config.fallbackEnabled ??= false;
        this.config.dynamicLanguageChange ??= false;
        const savedLocale = this.localeStore.locale;
        // The following check is important. We do not control the store and when it comes from
        // a remove backend, someone might give us a locale that we do not understand. In this
        // case we switch to the default.
        let initialLocale;
        const browserCultureLang = getBrowserCultureLanguage();
        const browserLang = getBrowserLanguage();
        if (this.hasLocale(savedLocale)) {
            initialLocale = savedLocale;
        }
        else if (this.translate.currentLanguage) {
            initialLocale = this.translate.currentLanguage;
        }
        else if (this.hasLocale(browserCultureLang)) {
            initialLocale = browserCultureLang;
        }
        else if (this.hasLocale(browserLang)) {
            initialLocale = browserLang;
        }
        else {
            initialLocale = this.config.defaultLocale;
        }
        this.locale$ = new BehaviorSubject(initialLocale);
        this.doSetLocale(initialLocale);
        // If a user changes the language on the translate service directly,
        // we synchronize the change again.
        this.translate.translationChange.subscribe(() => {
            const current = this.translate.currentLanguage;
            if (current) {
                this.locale = current;
            }
        });
        if (this.config.fallbackEnabled) {
            this.translate.setDefaultLanguage(this.config.defaultLocale);
        }
    }
    /**
     * Sets a new locale to the locale service and also to the translate
     * service.
     * @throws An error if the new value is not configured in the available locales
     * or if the new locale cannot be saved, an error is thrown.
     */
    set locale(value) {
        if (value === this.locale$.value || value === this._nextLocale) {
            return;
        }
        if (!this.hasLocale(value)) {
            throw new Error(`The value ${value} does not exist in the available locales.`);
        }
        this.localeStore
            .saveLocale(value)
            .pipe(first())
            .subscribe({
            next: (saveSucceed) => {
                if (saveSucceed) {
                    if (this.config.dynamicLanguageChange) {
                        this.doSetLocale(value);
                    }
                    else if (this.isBrowser) {
                        window.location.reload();
                    }
                }
                else {
                    throw new Error(`Could not save new locale ${value}.`);
                }
            },
            error: () => {
                throw new Error(`Could not save new locale ${value}.`);
            }
        });
    }
    get locale() {
        return this.locale$.value;
    }
    doSetLocale(value) {
        this._nextLocale = value;
        this.config.localeInitializer(value).then(() => {
            this.localePackageLoaded$.next();
            this.translate
                .setCurrentLanguage(value)
                .pipe(first())
                .subscribe(() => {
                if (this.locale$.value !== value) {
                    this.locale$.next(value);
                }
            });
        }, () => {
            console.error(`Could not initialize new locale ${value}. Setting default locale ${this.config.defaultLocale}`);
            // Initialization of locale rejected. Setting default locale.
            this.translate
                .setCurrentLanguage(this.config.defaultLocale)
                .pipe(first())
                .subscribe(() => {
                if (this.locale$.value !== this.config.defaultLocale) {
                    this.locale$.next(this.config.defaultLocale);
                }
            });
        });
    }
    /**
     * Test if the given locale is part of the available locales.
     * @param locale - The locale to be tested.
     */
    hasLocale(locale) {
        if (locale) {
            return this.config.availableLocales.includes(locale);
        }
        return false;
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiLocaleService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
    static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiLocaleService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiLocaleService, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }], ctorParameters: () => [] });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
/**
 * The SiLocaleId is used to provide a locale id from the translate service
 * to the angular localization. The Angular services call toString or valueOf
 * so that the current locale of the translation service is provided. The Intl.
 * library does not invoke toString() and using the value directly in Intl
 * formatting results always having the `en` locale. Thus, when using the SiLocaleId
 * in other services, make sure to use the `toString()` method before.
 */
class SiLocaleId extends String {
    service;
    // the constructor is needed for unknown reasons. w/o the inject() fails
    constructor() {
        super();
        this.service = inject(SiLocaleService);
    }
    /**
     * Outputs the locale id as a string.
     */
    toString() {
        return this.service.locale === 'template' ? 'en' : this.service.locale;
    }
    valueOf() {
        return this.toString();
    }
    toLowerCase() {
        return this.toString().toLowerCase();
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiLocaleId, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
    static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiLocaleId });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiLocaleId, decorators: [{
            type: Injectable
        }], ctorParameters: () => [] });

/**
 * Provider for dynamic CDK directionality.
 *
 * CDK per default evaluates directionality once during initialization. This is a problem when
 * switching language later in the lifecycle. This provider can be used to make this dynamic.
 * To use, simply provide this in the `ApplicationConfig`:
 *
 * ```ts
 * import { Directionality } from '@angular/cdk/bidi';
 * import { SiDirectionality } from '@siemens/element-ng/localization';
 *
 * ...
 * export const APP_CONFIG: ApplicationConfig = {
 *   providers: [
 *     { provide: Directionality, useClass: SiDirectionality },
 *     ...
 *   ]
 * }
 *
 * bootstrapApplication(AppComponent, APP_CONFIG)
 *    ...
 *
 * ```
 */
class SiDirectionality {
    change = new EventEmitter();
    /** @defaultValue 'ltr' */
    valueSignal = signal('ltr', ...(ngDevMode ? [{ debugName: "valueSignal" }] : []));
    get value() {
        const dir = isRTL() ? 'rtl' : 'ltr';
        this.valueSignal.set(dir);
        return dir;
    }
    /** @internal */
    // eslint-disable-next-line @angular-eslint/use-lifecycle-interface, @angular-eslint/no-empty-lifecycle-method
    ngOnDestroy() {
        // empty, from Directionality
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiDirectionality, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
    static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiDirectionality });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiDirectionality, decorators: [{
            type: Injectable
        }] });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */

/**
 * Generated bundle index. Do not edit.
 */

export { SI_LOCALE_CONFIG, SI_LOCALE_LOCAL_STORAGE_KEY, SI_LOCALE_STORE, SiDefaultLocaleStore, SiDirectionality, SiLocaleId, SiLocaleService, SiLocaleStore };
//# sourceMappingURL=siemens-element-ng-localization.mjs.map
