/*
 * Copyright 2017-2025 VMware, Inc. All rights reserved. VMware Confidential
 */

import { Injectable } from "@angular/core";
import { Observable, of, throwError as _throw } from "rxjs";
import { ExtensionLoaderStep, ExternalExtensionLoaderState } from "../extension-loader.model";
import { ExternalExtensionLoaderErrorObservable } from "./external-extension-loader-error";
import { logger } from "../../../../logging/logger";

export function getHashedString(vendor: string): string {
    return btoa(vendor);
}

@Injectable()
export class CreateExternalExtensionRouteStep implements ExtensionLoaderStep<ExternalExtensionLoaderState> {
    constructor() {}

    /**
     * Generate a route for the extension.
     * State inputs: manifest
     * State outputs: route
     */
    perform(state: ExternalExtensionLoaderState): Observable<ExternalExtensionLoaderState> {
        try {
            logger.log(`[${state.spec.id} (${state.manifest.name})] Generating extension route`);
            // this.mapLegacyPrimaryNavigationToPrimaryNavigationExtensionPoint(state);
            const routes = this.getRoutes(state);

            logger.log(`[${state.spec.id} (${state.manifest.name})] Extension route generated: ${routes}`);
            return of({ ...state, routes });
        } catch (err) {
            console.error(`[${state?.spec?.id} (${state?.manifest?.name})] Could not create extension route`, err);
            return new ExternalExtensionLoaderErrorObservable();
        }
    }

    getRoutes(state: ExternalExtensionLoaderState): {} {
        const routes = {};

        if (state.manifest.route) {
            routes[`${state.spec.id}`] = `${getHashedString(state.manifest.vendor)}/${state.manifest.route}`;
        }

        if (state.manifest.extensionPoints && state.manifest.extensionPoints.length) {
            state.manifest.extensionPoints.forEach((extensionPoint) => {
                if (!extensionPoint.route) {
                    return;
                }

                routes[`${state.spec.id}:${extensionPoint.urn}`] = extensionPoint.route;
            });
        }

        return routes;
    }

    /**
     * Legacy primary navigation extension points are those who don't have extension points array in their manifest.
     * This function covnerts this kind of "primary navigation" extension points to the actual format,
     * i.e store them in array.
     * 
     * Only one legacy extension point is allowed to be present in the extension points list.
     */
    private mapLegacyPrimaryNavigationToPrimaryNavigationExtensionPoint(state: ExternalExtensionLoaderState) {
        if (state.manifest.module && state.manifest.route) {
            if (!state.manifest.extensionPoints) {
                state.manifest.extensionPoints = [];
            }

            const alreadyMapped = state.manifest.extensionPoints.some((extPoint) => {
                return extPoint.urn === "legacy:primary:navigation";
            });
            if (alreadyMapped) {
                return;
            }
            
            const legacyPrimaryNavExtensionPoint = {
                urn: "legacy:primary:navigation",
                type: "navigation:primary",
                name: state.manifest.name,
                description: state.manifest.description,
                module: state.manifest.module,
                route: state.manifest.route,
            };
            state.manifest.extensionPoints.push(legacyPrimaryNavExtensionPoint);
        }
    }
}
