/*
 * ******************************************************************
 * Copyright (c) 2024 Broadcom. All Rights Reserved.
 * Broadcom Confidential. The term "Broadcom" refers to Broadcom Inc.
 * and/or its subsidiaries.
 * ******************************************************************
 */

import { Inject, Injectable, NgModuleRef } from "@angular/core";
import { Route, Router } from "@angular/router";
import { ExtensionComponentRegistration, ExtensionComponentRegistry } from "../extension-component.registry";
import { ExtensionContainerGuard } from "../extension-container/extension-container-guard";
import { ExtensionContainerComponent } from "../extension-container/extension-container.component";
import { ExtensionPointHandler } from "../extension-point.handler";
import { ExternalExtensionLoaderState } from "../loader/extension-loader.model";
import { getHashedString } from "../loader/external/create-external-extension-route.step";
import { HYPER_PLUGIN_CONFIG, HyperpluginConfig } from "../../../../lib-interfaces";
import { ExtensionPointRoutingHandler } from "../extension-point-routing.handler";
import { SERVICES_VCF_SCOPE, SERVICES_VCF_TYPE, SUPPORTED_VERSIONS } from "./vcf-services.constants";
import { VCFServicesExtensionPointManifest } from "./vcf-services.interfaces";

/**
 * This extension point handler supports extension manifests of version 9.1.0 and of type
 * "services:vcf". It will register the plugin modules directly in the VCF Services main navigation
 * of VCFA 9.
 */
@Injectable()
export class VCFServicesExtensionPointHandler implements ExtensionPointHandler {
    constructor(
        @Inject(HYPER_PLUGIN_CONFIG) private HYPER_PLUGIN_CONFIG: HyperpluginConfig,
        private extensionPointRoutingHandler: ExtensionPointRoutingHandler,
        private extensionComponentRegistry: ExtensionComponentRegistry,
        private router: Router,
    ) {}

    supports(version: string, type: string): boolean {
        return SUPPORTED_VERSIONS.indexOf(version) != -1 && type == SERVICES_VCF_TYPE;
    }

    bootstrap(
        extensionBundle: any,
        extensionAngularModule: NgModuleRef<any>,
        extensionPointManifest: VCFServicesExtensionPointManifest,
        ordering: number,
        state: ExternalExtensionLoaderState
    ): void {
        if (!extensionPointManifest.module && !extensionPointManifest.component) {
            throw new Error("VCF Services exptension point module/component is not defined in manifest.");
        }

        if (extensionPointManifest.module && extensionPointManifest.component) {
            throw new Error("VCF Services exptension point only module or component can be defined in manifest, not both.");
        }

        const vcdRoute = state.routes[`${state.spec.id}:${extensionPointManifest.urn}`];

        if (!vcdRoute) {
            throw new Error(`VCF Services exptension point '${extensionPointManifest.name}'
            defined a module/component but no route was found.`);
        }

        try {
            this.registerDynamicRoutesInStaticModule(state.manifest.vendor, vcdRoute);
        } catch (error) {
            throw Error(`Unable to register dynamic route ${vcdRoute}
            for extension point ${extensionPointManifest.name} in statc module.`);
        }

        const registration = new ExtensionComponentRegistration(
            SERVICES_VCF_SCOPE,
            extensionAngularModule,
            null,
            null,
            [],
            ordering,
            extensionPointManifest,
            state.manifest.locales,
            vcdRoute,
            getHashedString(state.manifest.vendor),
            null,
            state.spec.resourcePath,
        );
        this.extensionComponentRegistry.registerExtensionComponent(registration);
    }

    private registerDynamicRoutesInStaticModule(vendor: string,
        vcdRoute: string): void {
        const extensibleRoute = this.HYPER_PLUGIN_CONFIG.routes.filter((route) => {
            return route.type === SERVICES_VCF_TYPE;
        })[0];

        if (!extensibleRoute) {
            return;
        }

        const extensibleRouteSegments = extensibleRoute.path.split("/");
        const mainPath = extensibleRouteSegments[0];
        const childSegments = extensibleRouteSegments.slice(1);

        let mainRoute = this.router.config.find((route) => {
            return route.path === mainPath;
        });

        this.extensionPointRoutingHandler.findRouteChain(mainRoute, childSegments).subscribe((pluginsContainerRouter) => {  
            if (!pluginsContainerRouter.children) {
                pluginsContainerRouter.children = [];
            }
    
            const alreadyExistingRouteVendorRoute = pluginsContainerRouter.children.find((route) => {
                return route.path === getHashedString(vendor);
            });
    
            if (!alreadyExistingRouteVendorRoute) {
                const newRoute: Route = {
                    path: getHashedString(vendor),
                    children: [
                        {
                            path: "",
                            pathMatch: "full",
                            redirectTo: vcdRoute,
                        },
                        {
                            path: vcdRoute,
                            component: ExtensionContainerComponent,
                            data: {
                                vcdRoute,
                                fullHeight: extensibleRoute.fullHeight
                            },
                            canDeactivate: [ExtensionContainerGuard],
                            children: [
                                {
                                    path: "**",
                                    component: ExtensionContainerComponent,
                                    canDeactivate: [ExtensionContainerGuard],
                                },
                            ],
                        },
                    ],
                };
    
                pluginsContainerRouter.children.push(newRoute);
                return;
            }
    
            alreadyExistingRouteVendorRoute.children.push({
                path: vcdRoute,
                component: ExtensionContainerComponent,
                data: {
                    vcdRoute,
                    fullHeight: extensibleRoute.fullHeight,
                },
                canDeactivate: [ExtensionContainerGuard],
                children: [
                    {
                        path: "**",
                        component: ExtensionContainerComponent,
                        canDeactivate: [ExtensionContainerGuard],
                    },
                ],
            });
        });
    }
}
