/*
 * Copyright 2017-2025 VMware, Inc. All rights reserved. VMware Confidential
 */
import { NgModuleFactory, NgModuleRef, Type } from "@angular/core";
import { Observable } from "rxjs";
import { ExtensionManifest, ExtensionSpec } from "../extensibility.model";
import { TranslationSet } from "@vcd/i18n";

/**
 * The ongoing state while activating an external extension.
 * ExternalExtensionLoader will create a blank version of this state, and then
 * pass it through a sequence of ExtensionLoaderStep instances to load the extension.
 */
export interface ExternalExtensionLoaderState {
    /**
     * The backend-provided basic details about this extension.
     */
    spec: ExtensionSpec;

    /**
     * The loaded manifest for the extension.
     */
    manifest: ExtensionManifest;

    /**
     * The imported SystemJS bundle for the extension.
     */
    bundle: any;

    /**
     * Factory for creating the extension's angular module.
     */
    angularModuleFactories: {
        [id: string]: NgModuleFactory<any>;
    };

    /**
     * The instance of the extension's angular module.
     */
    angularModules: {
        [id: string]: NgModuleRef<any>;
    };

    /**
     * Global translations that the extension defines.
     */
    translations: TranslationSet;

    /**
     * The base route for the any of the extension module's routes.
     */
    routes: { [id: string]: string };
}

/**
 * The ongoing state while activating an internal extension.
 * InternalExtensionLoader will create a blank version of this state, and then
 * pass it through a sequence of ExtensionLoaderStep instances to load the extension.
 */
export interface InternalExtensionLoaderState {
    /**
     * The module representing this extension.
     */
    angularModuleType: Type<any> | NgModuleFactory<any>;

    /**
     * The name of the module representing this extension.
     */
    angularModuleName: string;

    /**
     * Factory for creating the extension's angular module.
     */
    angularModuleFactory: NgModuleFactory<any>;

    /**
     * The base route for the any of the extension module's routes.
     */
    route: string;
}

/**
 * Any of the above two loader states.  Used to make the next class definition more readable.
 */
export type LoaderState = InternalExtensionLoaderState | ExternalExtensionLoaderState;

/**
 * This is an abstract functor that represents a step performed while loading an extension.  This is used
 * by ExternalExtensionLoader and InternalExtensionLoader.
 *
 * A step is a minimal unit of work to be performed.  It takes an arbitrary starting state, and returns a
 * mutated state in future.
 *
 * Steps should be performed by flatMap-ing a sequence of them in order.
 */
export interface ExtensionLoaderStep<S extends LoaderState> {
    perform(state: S): Observable<S>;
}
