import { CoreTransformOrchestrator, IConfigRegistry, ITransformerRegistry, WrappedAsset, ITransformer, IConfigLoader, ConfigLoader, StudioAsset, ApiWithAssets, Metadata, MultiYamlFile } from "@apic/smith-transformer";
import { WMGWRuntimeInventory } from "@apic/wmgw-smith-inventory";
import { getParentDir } from "./path.util.js";
import yaml from 'js-yaml';
/**
 * WMGW implementation of the Transform Orchestrator
 * Specifically for transforming to WMGW gateway
 */
export class WmgwTransformerOrchestrator extends CoreTransformOrchestrator {

    /**
     * Create a new WMGW transform orchestrator
     * @param configRegistry Configuration registry
     * @param transformerRegistry Transformer registry
     */
    constructor(
        configRegistry: IConfigRegistry,
        transformerRegistry: ITransformerRegistry,
        configLoader: IConfigLoader
    ) {
        super(configRegistry, transformerRegistry, configLoader, '12.0.0');
        this.inventory = new WMGWRuntimeInventory();
    }

    /**
     * Post-transformation hook that organizes assets into execute, catch, and finally sections
     * @param transformedAssets Array of transformed assets
     * @param resources Resources extracted from the ZIP file
     * @param apiName Name of the API being processed
     * @param apiMetadata Metadata of the API
     * @returns Organized assets in assembly structure
     */

    protected processOriginalYamlFile(multiYamlFile: MultiYamlFile, transformedAssetsByApi: Record<string, { metadata: Metadata; output: any[]; }>, assetsByApi: Record<string, ApiWithAssets>): string {
        const validApiNames = Object.keys(transformedAssetsByApi);

        let validAssets: StudioAsset[] = this.filterAssets(multiYamlFile.assets.filter(asset => asset.kind.toLowerCase() !== 'freeflowpolicysequence'));

        const allApiNames = Object.keys(assetsByApi);

        const invalidApiNames = allApiNames.filter(apiName => (!validApiNames.includes(apiName)));

        for (const apiName of invalidApiNames) {
            if (assetsByApi[apiName]) {
                const apiAsset = assetsByApi[apiName].api;
                const relatedAssets = assetsByApi[apiName].relatedAssets;

                const apiAssetKey = `${apiAsset.kind}:${apiAsset.metadata.namespace || 'default'}:${apiAsset.metadata.name}:${apiAsset.metadata.version || '1.0'}`;
                const relatedAssetKeys = new Set(relatedAssets.map(asset => {
                    return `${asset.kind}:${asset.metadata.namespace || 'default'}:${asset.metadata.name}:${asset.metadata.version || '1.0'}`;
                }));

                validAssets = validAssets.filter(asset => {
                    const assetKey = `${asset.kind}:${asset.metadata.namespace || 'default'}:${asset.metadata.name}:${asset.metadata.version || '1.0'}`;

                    return assetKey !== apiAssetKey && !relatedAssetKeys.has(assetKey);
                });
            }
        }

        for (const apiName of validApiNames) {
            if (assetsByApi[apiName]) {
                validAssets.push(assetsByApi[apiName].api);

                validAssets.push(...assetsByApi[apiName].relatedAssets);
            }
        }

        const uniqueAssetsMap = new Map<string, StudioAsset>();

        for (const asset of validAssets) {
            const key = `${asset.kind}:${asset.metadata.namespace || 'default'}:${asset.metadata.name}:${asset.metadata.version || '1.0'}`;
            uniqueAssetsMap.set(key, asset);
        }

        const assetsInThisFile = Array.from(uniqueAssetsMap.values()).filter(asset => {
            return multiYamlFile.assets.some(
                fileAsset =>
                    fileAsset.metadata.name === asset.metadata.name &&
                    fileAsset.kind === asset.kind &&
                    (fileAsset.metadata.namespace || 'default') === (asset.metadata.namespace || 'default') &&
                    (fileAsset.metadata.version || '1.0') === (asset.metadata.version || '1.0')
            );
        });

        return assetsInThisFile
            .map(asset => yaml.dump(asset))
            .join('\n---\n');
    }

    protected isApiValid(api: StudioAsset, relatedAssets: StudioAsset[]): boolean {
        for (const asset of relatedAssets) {
            if (asset.kind.toLowerCase() === 'freeflowpolicysequence') {
                return false;
            }
            if (asset.kind.toLowerCase() === 'datapowerassembly') {
                return false;
            }
        }
        return true;
    }
}

/**
 * Factory function to create a WMGW transform orchestrator with default registries
 * @returns A new WMGW transform orchestrator
 */
export async function createWmgwOrchestrator(): Promise<WmgwTransformerOrchestrator> {
    const configLoader: IConfigLoader = new ConfigLoader(await getParentDir())
    const configRegistry: IConfigRegistry = {
        getConfigPath: (_sourceVersion: string, _targetVersion: string, _kind: string): string | undefined => {
            return './configs/skip-transform.json';
        }
    };

    const transformerRegistry: ITransformerRegistry = {
        getTransformer: (_name: string): ITransformer | undefined => {
            return undefined;
        }
    };

    return new WmgwTransformerOrchestrator(
        configRegistry,
        transformerRegistry,
        configLoader
    );
}

