/*!
 * Copyright (C) Microsoft Corporation. All rights reserved.
 */
import { processDataSourceInfo } from '../CodeGen/dataSourceInfoProcessor.js';
import { generateModelService } from '../CodeGen/modelServiceGenerator.js';
import { sanitizeName } from '../CodeGen/shared/nameUtils.js';
import { readRepoConfig, writeRepoConfig } from '../Config/ConfigManager.js';
import { initializePlayerActions } from '../initializePlayerActions.js';
import { upsertFlowConnectionReferences, } from '../ReferenceStores/connectionReferences.js';
import { getConnectionByNameAsync, getFlowMetadataAsync, getFlowSwaggerAsync, isConnectionShareable, } from '../services/index.js';
import { getVfs } from '../VfsManager.js';
import { FLOW_API_NAME, LOGIC_FLOWS_API_ID, SUPPORTED_TRIGGER_KINDS } from './flowConstants.js';
/**
 * Adds a flow by retrieving its metadata and swagger, updating the power.config file with the
 * appropriate connection references, and generating models and services from the flow's swagger.
 *
 * @param {AddFlowContext} context
 * @returns {Promise<AddFlowResult>}
 */
export async function addFlowAsync(context) {
    const { flowId } = context.actionsParams;
    initializePlayerActions({
        vfs: context.vfs,
        authProvider: context.authProvider,
        region: context.region,
        environmentName: context.environmentName,
        logger: context.logger,
    });
    try {
        const { powerConfigPath, schemaPath, codeGenPath } = context.localFilePaths;
        const vfs = getVfs();
        if (!(await vfs.exists(powerConfigPath))) {
            throw new Error(`Configuration file not found at ${powerConfigPath}`);
        }
        // Fetch metadata and swagger in parallel.
        const [flowMetadata, flowSwagger] = await Promise.all([
            getFlowMetadataAsync(flowId, context.logger),
            getFlowSwaggerAsync(flowId, context.logger),
        ]);
        // Validate that the flow has a supported trigger kind before proceeding.
        const triggers = flowMetadata.properties.definitionSummary?.triggers ?? [];
        const hasSupportedTrigger = triggers.some((t) => t.kind && SUPPORTED_TRIGGER_KINDS.has(t.kind));
        if (!hasSupportedTrigger) {
            const triggerKinds = triggers.map((t) => t.kind ?? t.type ?? 'unknown').join(', ') || 'unknown';
            throw new Error(`Flow '${flowMetadata.properties.displayName}' cannot be added to Code Apps. ` +
                `Only flows with a PowerApp or PowerAppV2 trigger are supported, ` +
                `but this flow has trigger kind: ${triggerKinds}.`);
        }
        const flowDisplayName = flowMetadata.properties.displayName;
        // Filter out only the dependencies with source "invoker", as those are the ones we need to add to the code repo config for authentication purposes.
        const invokerConnectionReferences = Object.fromEntries(Object.entries(flowMetadata.properties.connectionReferences).filter(([, connRef]) => connRef.source.toLowerCase() === 'invoker'));
        // Enrich each dependency with authenticationType and sharedConnectionId by querying
        // the connector and connection APIs. Throws if any connection cannot be accessed.
        const enrichedDependencies = await fetchEnrichedDependenciesAsync(invokerConnectionReferences, context.logger);
        // Update power.config with connection references for the flow and its dependencies.
        const config = await readRepoConfig(powerConfigPath);
        config.connectionReferences ??= {};
        upsertFlowConnectionReferences(config.connectionReferences, {
            flowDisplayName,
            workflowEntityId: flowMetadata.properties.workflowEntityId,
            flowDependencies: enrichedDependencies,
            workflowName: flowMetadata.name,
        });
        await writeRepoConfig(powerConfigPath, config);
        // Save the swagger as the flow's schema file.
        const schemaFilePath = await saveFlowSchema(flowSwagger, flowDisplayName, schemaPath);
        // Generate model services from the updated schema folder.
        await processDataSourceInfo(schemaPath, context.logger);
        await generateModelService({
            schemaFolderPath: schemaPath,
            codeGenPath,
            schemaFilePath,
            logger: context.logger,
        });
        return { success: true };
    }
    catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        return { success: false, error: errorMessage };
    }
}
/**
 * Fetches connector and connection details for each flow dependency in parallel,
 * returning an enriched record with `authenticationType` and `sharedConnectionId`.
 * Throws if any dependency connection cannot be retrieved (e.g. the user lacks access).
 */
async function fetchEnrichedDependenciesAsync(flowDependencies, logger) {
    const enrichedEntries = await Promise.all(Object.entries(flowDependencies).map(async ([connRefName, connRef]) => {
        const connector = connRef.apiDefinition;
        let connection;
        try {
            const maybeConnection = await getConnectionByNameAsync(connRef.connectionName, connector.name, logger);
            if (!maybeConnection) {
                throw new Error();
            }
            connection = maybeConnection;
        }
        catch (error) {
            throw new Error(`Unable to retrieve connection '${connRef.id}'. You may not have access to the underlying connections.`);
        }
        const authenticationType = connection.properties.connectionParametersSet?.name;
        const sharedConnectionId = authenticationType && isConnectionShareable(connector, authenticationType)
            ? connection.id
            : undefined;
        return [connRefName, { ...connRef, authenticationType, sharedConnectionId }];
    }));
    return Object.fromEntries(enrichedEntries);
}
/**
 * Saves the flow's swagger as a schema JSON file under schemaPath/logicflows/.
 * Returns the path of the saved file.
 */
async function saveFlowSchema(swagger, flowDisplayName, schemaPath) {
    const vfs = getVfs();
    const directoryPath = vfs.join(schemaPath, FLOW_API_NAME);
    const schemaFilePath = vfs.join(directoryPath, `${sanitizeName(flowDisplayName)}.Schema.json`);
    const fullSchema = {
        name: flowDisplayName,
        id: LOGIC_FLOWS_API_ID,
        type: 'Microsoft.PowerApps/apis',
        properties: {
            displayName: flowDisplayName,
            isCustom: false,
            swagger: swagger,
        },
    };
    await vfs.mkdir(directoryPath, { recursive: true });
    await vfs.writeFile(schemaFilePath, JSON.stringify(fullSchema, null, 2), { encoding: 'utf-8' });
    return schemaFilePath;
}
//# sourceMappingURL=AddFlow.js.map