/*
 * Copyright 2019-2022 VMware, Inc. All rights reserved. VMware Confidential
 */

import { NgModuleRef } from "@angular/core";
import { Routes } from "@angular/router";
import { TranslationSet } from "@vcd/i18n";

/**
 * This defines a formal extension point.  An extension point is a declarative way for an extension manifest
 * to describe how the VCD application behaviour is extended or modified by the extension.
 */
export interface ExtensionPointManifest {
    /**
     * Universally unique URN that identifies this Extension Point.  It is suggested to preprend the extension's URN.
     */
    readonly urn: string;

    /**
     * The type of Extension Point being defined from a supported list.  This list will increase over time.
     */
    readonly type: string;

    /**
     * The name of the Extension Point, intended for display in extension management interfaces.
     */
    readonly name: string;

    /**
     * An overview of the Extension Point, intended for display in extension management interfaces.
     */
    readonly description: string;

    /**
     * The name of the module which will be registerd in the top-nav-level area.
     */
    readonly module?: string;

    /**
     * The route on which only top level extrension points will be registerd.
     */
    readonly route?: string;

    /**
     * This property will be defiend by the Plugin Writer and will specify the location
     * where his extension will be rendered (Supported Locations Only).
     *
     * After/Before certain css selector
     */
    readonly render?: {
        after?: string;
        before?: string;
    };

    /**
     * Anuglar app custom styles and scripts list, loaded inside the shadow dom by the Core UI
     */
    styles?: string[];
    scripts?: string[];
}

/**
 * Supported extension scopes.
 */
export type ExtensionScope = "tenant" | "service-provider";

/**
 * Supported extension manifest versions.
 */
export enum EXTENSION_MANIFEST_VERSIONS {
    "1.0.0" = "1.0.0",
    "2.0.0" = "2.0.0",
}

/**
 * The contents of a third party extension's manifest.json file.
 */
export interface ExtensionManifest {
    /**
     * The version of the manifest
     */
    manifestVersion: string;

    /**
     * Unique URN used an ID for the extension.
     */
    urn: string;

    /**
     * Human readable name for the extension.
     */
    name: string;

    /**
     * The minimum supported version of VCD UI.
     * TODO: Not currently used.
     */
    containerVersion: string;

    /**
     * Versions of VCD that the plugin claims compatibility with.
     */
    productVersions: string[];

    /**
     * The version of the extension.
     */
    version: string;

    /**
     * Scopes that the extension may be used under (e.g. tenant, service-provider).
     */
    scope: ExtensionScope[];

    /**
     * Minimum permissions required for the extension to be loaded.
     */
    permissions: string[];

    /**
     * Human readable description for the extension.
     */
    description: string;

    /**
     * Human readable vendor name for the extension.
     */
    vendor: string;

    /**
     * Human readable license information for the extension.
     */
    license: string;

    /**
     * Support URL for the extension.
     */
    link: string;

    /**
     * The symbol to be imported as an Angular 4 module from the
     * the extension's AMD bundle.
     */
    module?: string;

    /**
     * The base route the extension's routes will be registered under.
     */
    route?: string;

    /**
     * Formal extension points.
     */
    extensionPoints?: ExtensionPointManifest[];

    /**
     * Extension locales for the manifest.
     * Supported by manifest v2.0.0 and higher.
     */
    locales: TranslationSet;

    externals?: {
        libs: {
            [libName: string]: {
                version: string;
                scope: ExtensionLibScope;
                location: string;
            };
        };
        jsonpFunction: string;
    };

    /**
     * Containes the base px value of a plugin, used by the Core UI to calculate the rem scaler.
     */
    pluginBasePx?: number;
}

export type ExtensionLibScope = "external" | "bundled" | "isolated";

/**
 * Backend model for a plugin.
 */
export interface ExtensionSpec {
    /**
     * Opaque unique ID for the plugin on the backend.
     */
    id: string;

    /**
     * Base path for the plugin contents.
     */
    resourcePath: string;
}

export type LifeCycleFn<T> = (config: T) => Promise<Promise<void> | Promise<NgModuleRef<any>>>;
export interface AngularAppBundle<T> {
    bootstrap: LifeCycleFn<T>;
    activate: LifeCycleFn<T>;
    deactivate: LifeCycleFn<T>;
    ROUTES: Routes;
    template: string;
    systemJsSetup?: Function;
    loadPlugins?: Function;
    customWindow?: any;
}

/**
 * Stores loaded manifests in window object to be re-used,
 * if needed.
 *
 * Spec id can be obtained from window["_bootstrapDetails"].thirdPartyExtensions
 */
export interface UiPluginsManifestCache {
    [specId: string]: ExtensionManifest;
}
export const UI_PLUGINS_MANIFEST_CACHE = "__vmware_cloud_director_uiPluginManifestCache";