import * as i0 from '@angular/core';
import { Injectable, Optional } from '@angular/core';
import * as i2 from '@c8y/ngx-components';
import { colorValidator } from '@c8y/ngx-components';
import { applyBrandingOptions, getOptionsToMerge, mergeOptions } from '@c8y/bootstrap';
import chroma from 'chroma-js';
import * as i1 from '@c8y/client';
import { ApplicationAvailability, ApplicationType } from '@c8y/client';
import { BehaviorSubject, defer } from 'rxjs';
import { switchMap, map } from 'rxjs/operators';
import { uniq, cloneDeep } from 'lodash-es';
import * as i4 from '@c8y/ngx-components/static-assets/data';

class ApplyBrandingLocallyService {
    constructor(options) {
        this.options = options;
    }
    applyBranding(optionsJson) {
        if (!this.keysToRemove) {
            this.keysToRemove = Object.keys(this.combineOptions());
        }
        const combinedOptions = this.combineOptions(optionsJson);
        const newKeysToRemove = Object.keys(combinedOptions);
        // avoid to remove keys that would actually be set again afterwards
        const keysToActuallyRemove = this.keysToRemove.filter(key => !newKeysToRemove.includes(key));
        this.removeKeysFromOptions(keysToActuallyRemove);
        this.keysToRemove = newKeysToRemove;
        applyBrandingOptions(combinedOptions);
        this.applyApplicationOptions(combinedOptions);
    }
    resetBranding() {
        this.applyBranding();
    }
    applyApplicationOptions(optionsJson) {
        Object.entries(optionsJson).forEach(([key, value]) => {
            this.options.set(key, value);
        });
    }
    removeKeysFromOptions(keys) {
        for (const key of keys) {
            this.options.delete(key);
        }
    }
    combineOptions(optionsJson) {
        const optionsToMerge = getOptionsToMerge();
        if (!optionsToMerge) {
            // should never happen as the options should be set quite early in bootstrapping process.
            throw Error(`Failed to retrieve options for merging`);
        }
        if (optionsJson) {
            optionsToMerge.dynamicOptions = optionsJson;
        }
        return mergeOptions(optionsToMerge);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ApplyBrandingLocallyService, deps: [{ token: i2.OptionsService }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ApplyBrandingLocallyService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ApplyBrandingLocallyService, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }], ctorParameters: () => [{ type: i2.OptionsService }] });

class BrandingShadesService {
    getShadeColorBrandingCssVars(newBrandPrimary) {
        const shades = this.generateShades(newBrandPrimary);
        return this.shadesToObject(shades);
    }
    isValidShadeColor(color) {
        try {
            return chroma.valid(color);
        }
        catch {
            return false;
        }
    }
    hasCustomShadesSet(previousBrandPrimary, otherVars) {
        if (previousBrandPrimary && otherVars) {
            const oldShades = this.generateShades(previousBrandPrimary);
            const oldShadesObj = this.shadesToObject(oldShades);
            for (const shadeKey of Object.keys(oldShadesObj)) {
                const fromVars = otherVars[shadeKey];
                const generated = oldShadesObj[shadeKey];
                if (fromVars === null || fromVars === undefined) {
                    continue;
                }
                if (fromVars !== generated) {
                    return true;
                }
            }
        }
        return false;
    }
    shadesToObject(shades) {
        const brandingCssVars = {};
        let i = 1;
        for (const shade of shades) {
            const key = `c8y-brand-${i}0`;
            brandingCssVars[key] = shade;
            i++;
        }
        return brandingCssVars;
    }
    generateShades(inputColor) {
        const referenceShades = [
            '#134158',
            '#1C5569',
            '#058192', // primary color
            '#22A6AA',
            '#3CC1B7',
            '#8ADBD5',
            '#C5EDEA',
            '#EBF9F8'
        ];
        // Calculate the luminance of the reference shades
        const referenceLuminances = referenceShades.map(color => chroma(color).luminance());
        const inputColorAsHex = chroma(inputColor);
        // Generate shades of the input color with the same luminance as the reference shades
        const generatedShades = referenceLuminances.map(luminance => chroma(inputColor).luminance(luminance).hex('rgb'));
        // Calculate the distance between the input color and each color in the generatedShades array
        const distances = generatedShades.map(color => chroma.deltaE(inputColorAsHex, color));
        // Find the index of the color with the smallest distance
        const index = distances.indexOf(Math.min(...distances));
        generatedShades[index] = inputColorAsHex.hex('rgb');
        return generatedShades;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: BrandingShadesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: BrandingShadesService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: BrandingShadesService, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }] });

/**
 * Service for creating and manipulating branding versions.
 */
class BrandingVersionService {
    static { this.nameAndIterationSeparator = '-'; }
    /**
     * Creates the initial branding version for a given name.
     * @param name The name of the branding.
     * @returns The initial branding version.
     */
    createInitialBrandingVersion(name) {
        return `${name}${BrandingVersionService.nameAndIterationSeparator}${1}`;
    }
    /**
     * Splits a branding version into its name and iteration.
     * @param version The branding version to split.
     * @returns The name and iteration of the branding version.
     *
     * Errors are thrown if the version is not in the expected format.
     */
    splitBrandingIntoNameAndIteration(version) {
        const splitted = version.split(BrandingVersionService.nameAndIterationSeparator);
        if (splitted.length < 2) {
            throw Error(`A valid version should at least conatin one '${BrandingVersionService.nameAndIterationSeparator}', this is not the case for '${version}'`);
        }
        const lastValueOfSplittedArray = splitted[splitted.length - 1];
        if (lastValueOfSplittedArray === '' || !/[0-9]+/.test(lastValueOfSplittedArray)) {
            throw Error(`The second part of the version should be a positive integer, this is not the case for '${lastValueOfSplittedArray}' from '${version}'`);
        }
        const iteration = Number.parseInt(lastValueOfSplittedArray);
        if (Number.isNaN(iteration) && iteration <= 0) {
            throw Error(`The second part of the version should be a positive integer, this is not the case for '${iteration}' from '${version}'`);
        }
        const name = splitted.slice(0, -1).join(BrandingVersionService.nameAndIterationSeparator);
        if (!name) {
            throw Error(`The first part of the version should not be empty, this is the case for '${name}' from '${version}'`);
        }
        return { iteration, name };
    }
    /**
     * Bumps the iteration of a branding version.
     * @param version The branding version to bump.
     * @returns The bumped branding version.
     *
     * Errors are thrown if the version is not in the expected format.
     */
    bumpBrandingIteration(version) {
        const { name, iteration } = this.splitBrandingIntoNameAndIteration(version);
        return `${name}${BrandingVersionService.nameAndIterationSeparator}${iteration + 1}`;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: BrandingVersionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: BrandingVersionService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: BrandingVersionService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }] });

const brandingFormGroupTopLevelEntries = [
    'cookieBanner',
    'genericApplicationOptions',
    'darkThemeAvailable',
    'messageBanner'
];
const brandingFormGroupTopLevelEntriesToUnpack = [
    'genericApplicationOptions'
];
const numberBrandingVars = ['brand-logo-img-height', 'btn-border-radius-base'];
const colorBrandingVars = [
    'brand-dark',
    'brand-light',
    'brand-primary',
    'c8y-brand-10',
    'c8y-brand-20',
    'c8y-brand-30',
    'c8y-brand-40',
    'c8y-brand-50',
    'c8y-brand-60',
    'c8y-brand-70',
    'c8y-brand-80',
    'palette-status-info',
    'palette-status-warning',
    'palette-status-success',
    'palette-status-danger',
    'palette-status-info-light',
    'palette-status-warning-light',
    'palette-status-success-light',
    'palette-status-danger-light',
    'palette-status-info-dark',
    'palette-status-warning-dark',
    'palette-status-success-dark',
    'palette-status-danger-dark',
    'body-background-color',
    'text-color',
    'text-muted',
    'link-color',
    'link-hover-color',
    'action-bar-background-default',
    'action-bar-color-actions-hover',
    'action-bar-color-actions',
    'action-bar-color-default',
    'action-bar-icon-color',
    'header-color',
    'header-text-color',
    'header-hover-color',
    'navigator-bg-color',
    'navigator-active-bg',
    'navigator-border-active',
    'navigator-header-bg',
    'navigator-title-color',
    'navigator-separator-color',
    'navigator-text-color',
    'navigator-color-active',
    'right-drawer-background-default',
    'right-drawer-text-color-default',
    'right-drawer-separator-color',
    'right-drawer-link-color',
    'right-drawer-link-color-hover',
    'right-drawer-text-color-muted'
];
const stringBrandingVars = [
    'brand-logo-img',
    'navigator-platform-logo',
    'login-platform-animation-img'
];
const stringOrNumberBrandingVars = ['navigator-platform-logo-height'];
const allBrandingCSSVars = [
    ...numberBrandingVars,
    ...stringBrandingVars,
    ...colorBrandingVars
];
function createGenericBrandingForm(formBuilder) {
    const form = formBuilder.group({
        darkThemeAvailable: formBuilder.control(false),
        cookieBanner: formBuilder.group({
            cookieBannerTitle: formBuilder.control(undefined),
            cookieBannerText: formBuilder.control(undefined),
            cookieBannerDisabled: formBuilder.control(false),
            policyUrl: formBuilder.control(undefined),
            policyVersion: formBuilder.control(undefined)
        }),
        messageBanner: formBuilder.group({
            messageBannerEnabled: formBuilder.control(false),
            messageBannerContent: formBuilder.control(''),
            messageBannerType: formBuilder.control('info'),
            messageBannerId: formBuilder.control('')
        }),
        baseTypography: formBuilder.group({
            'font-url': formBuilder.control(undefined),
            'font-family-base': formBuilder.control(undefined)
        }),
        headingsAndNavigatorTypography: formBuilder.group({
            'font-family-headings': formBuilder.control(undefined),
            'navigator-font-family': formBuilder.control('var(--font-family-base)')
        }),
        genericApplicationOptions: formBuilder.group({
            globalTitle: formBuilder.control(undefined),
            faviconUrl: formBuilder.control(undefined)
        })
    });
    return form;
}
function createBrandingForm(formBuilder) {
    const colorControls = colorBrandingVars.reduce((acc, key) => {
        acc[key] = formBuilder.control(undefined, { asyncValidators: [colorValidator()] });
        return acc;
    }, {});
    const stringControls = stringBrandingVars.reduce((acc, key) => {
        acc[key] = formBuilder.control(undefined);
        return acc;
    }, {});
    const numberControls = numberBrandingVars.reduce((acc, key) => {
        acc[key] = formBuilder.control(undefined);
        return acc;
    }, {});
    const stringOrNumberControls = stringOrNumberBrandingVars.reduce((acc, key) => {
        acc[key] = formBuilder.control(undefined);
        return acc;
    }, {});
    const form = formBuilder.group({
        ...colorControls,
        ...stringControls,
        ...numberControls,
        ...stringOrNumberControls
    });
    return form;
}

class BrandingTrackingService {
    constructor(gainsight) {
        this.gainsight = gainsight;
        this.prefix = 'brandingManager';
    }
    getStartedUsingBranding() {
        this.triggerEvent('getStartedUsingBranding');
    }
    deleteAllBrandings() {
        this.triggerEvent('deleteAllBrandings');
    }
    exportBranding() {
        this.triggerEvent('exportBranding');
    }
    addNewVersion() {
        this.triggerEvent('addNewVersion');
    }
    duplicateVersion() {
        this.triggerEvent('duplicateVersion');
    }
    applyToApps(apps) {
        this.triggerEvent('applyToApps', { apps });
    }
    importBranding() {
        this.triggerEvent('importBranding');
    }
    deleteBrandingVariant() {
        this.triggerEvent('deleteBrandingVariant');
    }
    openPreviewForBranding() {
        this.triggerEvent('openPreviewForBranding');
    }
    triggerEvent(action, props) {
        if (!this.gainsight) {
            return;
        }
        const finalProps = {
            ...props,
            action
        };
        return this.gainsight.triggerEvent(this.prefix, finalProps);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: BrandingTrackingService, deps: [{ token: i2.GainsightService, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: BrandingTrackingService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: BrandingTrackingService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }], ctorParameters: () => [{ type: i2.GainsightService, decorators: [{
                    type: Optional
                }] }] });

/**
 * Service to load and store the branding of the tenant.
 */
class StoreBrandingService {
    constructor(applicationService, inventory, binary, zip, fetch, brandingVersionService, appState, staticAssets, themeSwitcher, brandingTracking) {
        this.applicationService = applicationService;
        this.inventory = inventory;
        this.binary = binary;
        this.zip = zip;
        this.fetch = fetch;
        this.brandingVersionService = brandingVersionService;
        this.appState = appState;
        this.staticAssets = staticAssets;
        this.themeSwitcher = themeSwitcher;
        this.brandingTracking = brandingTracking;
        this.fileNames = {
            options: 'options.json',
            manifest: 'cumulocity.json',
            exportZipName: 'public-options.zip'
        };
        this.manifestValues = {
            name: 'public-options',
            contextPath: 'public-options',
            key: 'public-options-key',
            description: 'Application containing static assets used by e.g. branding.',
            noAppSwitcher: true,
            type: ApplicationType.HOSTED,
            availability: ApplicationAvailability.SHARED
        };
        this.refreshTriggerBrandingVariants = new BehaviorSubject(null);
    }
    /**
     * Sets the `latest` tag on the provided branding version. Making it the global active branding.
     */
    async markAsActive(brandingVersion, app) {
        const publicOptions = app || (await this.getPublicOptionsApp());
        const tags = brandingVersion.tags || [];
        const version = brandingVersion.version;
        await this.applicationService.setPackageVersionTag(publicOptions, version, [...tags, 'latest']);
    }
    /**
     * Opens a new tab with to preview the branding. The branding must have been saved beforehand.
     * @param brandingName the name of the branding to be previewed
     */
    openPreviewForBranding(brandingName) {
        this.brandingTracking.openPreviewForBranding();
        window.open(`/apps/${this.appState.currentApplication.value?.contextPath || 'cockpit'}/index.html?brandingPreview=true&dynamicOptionsUrl=/apps/public/public-options@${brandingName}/options.json`, '_blank', 'noopener,noreferrer');
    }
    /**
     * Returns the brandings of the tenant.
     * If no public options app is found, publicOptions will be undefined and variants an empty array.
     * For old brandings (created without versioning) a default version is returned.
     */
    async loadBrandingVariants(app) {
        const publicOptions = app || (await this.getPublicOptionsApp());
        if (!publicOptions) {
            return { publicOptions: undefined, variants: [] };
        }
        const { data: versions } = await this.applicationService.listVersions(publicOptions);
        let mappedVersions = versions
            ?.map(tmp => {
            try {
                const { name, iteration } = this.brandingVersionService.splitBrandingIntoNameAndIteration(tmp.version);
                return {
                    revision: iteration,
                    name: name,
                    id: tmp.binaryId,
                    version: tmp.version,
                    tags: tmp.tags || [],
                    publicOptionsApp: publicOptions
                };
            }
            catch (e) {
                console.warn('Failed to parse version', tmp, e);
                return undefined;
            }
        })
            ?.filter(Boolean) || [];
        if (!versions && publicOptions.activeVersionId) {
            mappedVersions = [
                {
                    name: 'default',
                    id: publicOptions.activeVersionId,
                    version: 'default-1',
                    revision: 1,
                    tags: ['latest', 'default'],
                    publicOptionsApp: publicOptions
                }
            ];
        }
        const variants = await this.getMetadataOfBrandingBinaries(mappedVersions);
        return { publicOptions, variants };
    }
    /**
     * As the branding is not immediately available after creation, this method will wait for the branding to be present.
     * @param version The version of the branding to be retrieved.
     */
    async waitForBrandingToBePresent(version) {
        const numberOfAttempts = 120;
        const sleepDurationInSeconds = 1;
        for (let i = 0; i < numberOfAttempts; i++) {
            try {
                // do not sleep before the first attempt
                if (i !== 0) {
                    await new Promise(resolve => setTimeout(resolve, sleepDurationInSeconds * 1_000));
                }
                await this.getBrandingOptionsForVersion(version);
                console.info(`Branding "${version}" available now.`);
                return;
            }
            catch (e) {
                console.warn(`Branding "${version}" not yet present, retrying in ${sleepDurationInSeconds} seconds...`, e);
            }
        }
        throw new Error(`Branding "${version}" not available after ${numberOfAttempts * sleepDurationInSeconds} seconds, giving up.`);
    }
    /**
     * Will create a the initial branding based on the currently applied CSS variables.
     */
    async getStartedUsingBranding() {
        const allVariables = {};
        const themeToRetrieveVars = ['light', 'dark'];
        const unretrievableVars = new Array();
        for (const theme of themeToRetrieveVars) {
            this.themeSwitcher.temporaryChangeTheme(theme);
            const styles = getComputedStyle(document.body);
            const variablesToSkip = [
                'navigator-platform-logo',
                'brand-logo-img'
            ];
            const values = allBrandingCSSVars
                .filter(cssVar => !variablesToSkip.includes(cssVar))
                .reduce((prev, key) => {
                const directValue = styles.getPropertyValue(`--${key}`);
                const c8yPrefixedValue = styles.getPropertyValue(`--c8y-${key}`);
                const newKey = theme === 'light' ? key : `dark-${key}`;
                if (!directValue && !c8yPrefixedValue) {
                    unretrievableVars.push(newKey);
                    return prev;
                }
                let value = directValue || c8yPrefixedValue;
                if (numberBrandingVars.includes(key)) {
                    try {
                        value = Number.parseFloat(value.replace(/[A-Za-z]/g, '').trim());
                    }
                    catch (e) {
                        console.warn(`Failed to parse number for "${key}" value that failed to parse: "${value}"`, e);
                        return prev;
                    }
                }
                return Object.assign(prev, { [newKey]: value });
            }, {});
            Object.assign(allVariables, values);
        }
        this.themeSwitcher.resetTemporaryTheme();
        try {
            await this.createPublicOptionsAppFromInheritedOptions(allVariables);
        }
        catch (e) {
            console.warn(e);
        }
    }
    getZipForBinary(binaryId, fileName = this.fileNames.exportZipName) {
        return defer(() => this.binary.download(binaryId)).pipe(switchMap(response => response.blob()), map(blob => new File([blob], fileName)));
    }
    /**
     * Deletes the public options app and therefore all brandings.
     * The public options app can be optionally provided to avoid another request for it.
     */
    async deleteAllBrandings(publicOptions) {
        publicOptions = publicOptions || (await this.getPublicOptionsApp());
        await this.applicationService.delete(publicOptions);
    }
    /**
     * Enhances the provided branding versions with metadata from the linked binaries.
     * It will add the owner and lastUpdated fields to the versions.
     * The provided array is altered.
     */
    async getMetadataOfBrandingBinaries(versions) {
        const binaryIds = uniq(versions.map(tmp => tmp.id));
        if (!binaryIds.length) {
            return versions;
        }
        const { data: metadata } = await this.inventory.list({
            ids: binaryIds.join(','),
            pageSize: 2000
        });
        return versions.map(version => {
            const metadataForVersion = metadata.find(tmp => tmp.id === version.id) || {};
            const { owner, lastUpdated } = metadataForVersion;
            return Object.assign(version, { owner, lastUpdated });
        });
    }
    /**
     * Saves the provided branding as a new version for the public options app.
     * The public options app can be optionally provided to avoid another request for it.
     */
    async saveBranding(blob, version, tags = [], publicOptionsApp) {
        const file = blob instanceof File ? blob : new File([blob], `public-options-${version}.zip`);
        const publicOptions = publicOptionsApp || (await this.getPublicOptionsApp());
        const { data: binary } = await this.applicationService
            .binary(publicOptions)
            .uploadApplicationVersion(file, version, tags);
        if (!publicOptions.activeVersionId || tags.includes('latest')) {
            await this.applicationService.update({
                id: publicOptions.id,
                activeVersionId: `${binary.binaryId}`
            });
        }
        this.refreshTriggerBrandingVariants.next();
        return { version, binary, tags };
    }
    /**
     * Removes a branding version from the public options app.
     * The public options app can be optionally provided to avoid another request for it.
     */
    async deleteBrandingVersion(version, publicOptions) {
        publicOptions = publicOptions || (await this.getPublicOptionsApp());
        await this.applicationService.deleteVersionPackage(publicOptions, { version });
        this.refreshTriggerBrandingVariants.next();
    }
    /**
     * Returns the blob of a zip file containing the provided branding options (options.json) and the manifest (cumulocity.json).
     */
    async getBrandingZip(content = {}) {
        content.lastUpdated = new Date().toISOString();
        const contentAsString = JSON.stringify(content);
        const zip = await this.zip.createZip([
            { fileName: this.fileNames.options, blob: new Blob([contentAsString]) },
            { fileName: this.fileNames.manifest, blob: new Blob([JSON.stringify(this.manifestValues)]) }
        ]);
        return zip;
    }
    /**
     * Adds a new branding version to the public options app.
     * The public options app can be optionally provided to avoid another request for it.
     */
    async addBranding(version, content = {}, tags = [], publicOptionsApp) {
        const zip = await this.getBrandingZip(content);
        return await this.saveBranding(zip, version, tags, publicOptionsApp);
    }
    /**
     * Returns the branding options for the provided version.
     * If no branding was found (e.g. status 404), an error is thrown.
     */
    async getBrandingOptionsForVersion(version) {
        const url = `/apps/public/public-options${version ? `@${version}` : ''}/${this.fileNames.options}`;
        const response = await this.fetch.fetch(url, { cache: 'no-cache' });
        if (response.status !== 200) {
            throw Error(`Unexpected status code: ${response.status}`);
        }
        const content = await response.json();
        return content;
    }
    /**
     * Saves a new iteration of an already existing branding.
     */
    async saveExistingBranding(branding, currentVersion, tagsOfCurrentVersion = [], newVersion) {
        const publicOptions = await this.getPublicOptionsApp();
        const versionToBeSet = newVersion
            ? this.brandingVersionService.createInitialBrandingVersion(newVersion)
            : this.brandingVersionService.bumpBrandingIteration(currentVersion);
        const finalTags = tagsOfCurrentVersion;
        // only apply latest tag directly
        // there seems to be some special handling for the latest tag in the backend, that allows to directly move it while uploading the new version.
        // for all other tags this results in a 409 conflict. We therefore need to first delete the old version, before setting the other tags on the new version.
        if (!newVersion) {
            tagsOfCurrentVersion = tagsOfCurrentVersion.filter(tag => tag === 'latest');
        }
        await this.addBranding(versionToBeSet, branding, tagsOfCurrentVersion, publicOptions);
        if (!newVersion) {
            try {
                await this.deleteBrandingVersion(currentVersion, publicOptions);
            }
            catch (e) {
                if (e.res.status !== 404) {
                    throw e;
                }
            }
            await this.applicationService.setPackageVersionTag(publicOptions, versionToBeSet, finalTags);
        }
        return versionToBeSet;
    }
    /**
     * Combines current branding options with the provided branding variables and creates a new public options app.
     * Any assets in the branding will be cloned.
     */
    async createPublicOptionsAppFromInheritedOptions(brandingVars) {
        let currentlyAppliedBranding;
        let fallBackBranding = {};
        try {
            currentlyAppliedBranding = await this.getBrandingOptionsForVersion();
            fallBackBranding = cloneDeep(currentlyAppliedBranding);
        }
        catch (e) {
            console.warn('Failed to get currently applied branding, proceeding with empty branding.', e);
        }
        if (brandingVars) {
            currentlyAppliedBranding = currentlyAppliedBranding || {};
            const brandingCssVars = currentlyAppliedBranding.brandingCssVars || {};
            Object.assign(brandingCssVars, brandingVars);
            currentlyAppliedBranding.brandingCssVars = brandingCssVars;
        }
        if (currentlyAppliedBranding) {
            try {
                const { oldAssets, newAssets } = await this.staticAssets.cloneAssetsIntoTenant('branding');
                currentlyAppliedBranding = this.replaceBrandingAssetsInBrandingOptions(currentlyAppliedBranding, oldAssets, newAssets);
            }
            catch (e) {
                console.warn('Failed to relocate branding assets into current tenant.', e);
            }
        }
        const publicOptionsApp = await this.createPublicOptionsApp();
        const defaultBrandingName = `default`;
        const result = await this.addBranding(this.brandingVersionService.createInitialBrandingVersion(defaultBrandingName), currentlyAppliedBranding || {}, ['latest', defaultBrandingName], publicOptionsApp);
        const fallbackBrandingName = `fallback`;
        await this.addBranding(this.brandingVersionService.createInitialBrandingVersion(fallbackBrandingName), fallBackBranding, [fallbackBrandingName], publicOptionsApp);
        return result;
    }
    /**
     * Replaces the assets in the branding options with the new assets.
     * Goes through the provided `oldAssets` and replaces their occurrences in the branding with the corresponding `newAssets` entry sharing the same fileName.
     * Returns the updated branding options.
     */
    replaceBrandingAssetsInBrandingOptions(branding, oldAssets, newAssets) {
        let brandingAsJSONString = JSON.stringify(branding);
        for (const oldAsset of oldAssets) {
            const newLocatedAsset = newAssets.find(tmp => tmp.fileName === oldAsset.fileName);
            if (!newLocatedAsset) {
                continue;
            }
            // if the path is the same, we don't need to replace it.
            if (oldAsset.path === newLocatedAsset.path) {
                continue;
            }
            // TODO: use proper replaceAll once it's available with es2021
            brandingAsJSONString = brandingAsJSONString.split(oldAsset.path).join(newLocatedAsset.path);
        }
        return JSON.parse(brandingAsJSONString);
    }
    async getPublicOptionsApp() {
        try {
            const { data: manifest } = await this.applicationService.getManifestOfContextPath(this.manifestValues.contextPath);
            const { data: app } = await this.applicationService.detail(manifest.id);
            if (app.owner.tenant.id !== this.appState.currentTenant.value?.name) {
                return undefined;
            }
            return app;
        }
        catch (e) {
            // e.g. reached when no app with the given context path exists
            return undefined;
        }
    }
    async createPublicOptionsApp() {
        const { data: app } = await this.applicationService.create(this.manifestValues);
        return app;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: StoreBrandingService, deps: [{ token: i1.ApplicationService }, { token: i1.InventoryService }, { token: i1.InventoryBinaryService }, { token: i2.ZipService }, { token: i1.FetchClient }, { token: BrandingVersionService }, { token: i2.AppStateService }, { token: i4.StaticAssetsService }, { token: i2.ThemeSwitcherService }, { token: BrandingTrackingService }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: StoreBrandingService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: StoreBrandingService, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }], ctorParameters: () => [{ type: i1.ApplicationService }, { type: i1.InventoryService }, { type: i1.InventoryBinaryService }, { type: i2.ZipService }, { type: i1.FetchClient }, { type: BrandingVersionService }, { type: i2.AppStateService }, { type: i4.StaticAssetsService }, { type: i2.ThemeSwitcherService }, { type: BrandingTrackingService }] });

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

export { ApplyBrandingLocallyService, BrandingShadesService, BrandingTrackingService, BrandingVersionService, StoreBrandingService, allBrandingCSSVars, brandingFormGroupTopLevelEntries, brandingFormGroupTopLevelEntriesToUnpack, colorBrandingVars, createBrandingForm, createGenericBrandingForm, numberBrandingVars, stringBrandingVars, stringOrNumberBrandingVars };
//# sourceMappingURL=c8y-ngx-components-branding-shared-data.mjs.map
