"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DynamicNodeParametersService = void 0;
const di_1 = require("@n8n/di");
const n8n_core_1 = require("n8n-core");
const n8n_workflow_1 = require("n8n-workflow");
const node_types_1 = require("../node-types");
const credentials_finder_service_1 = require("../credentials/credentials-finder.service");
const forbidden_error_1 = require("../errors/response-errors/forbidden.error");
const workflow_loader_service_1 = require("./workflow-loader.service");
const db_1 = require("@n8n/db");
const check_access_1 = require("../permissions.ee/check-access");
const backend_common_1 = require("@n8n/backend-common");
let DynamicNodeParametersService = class DynamicNodeParametersService {
    constructor(logger, nodeTypes, workflowLoaderService, sharedWorkflowRepository, credentialsFinderService) {
        this.logger = logger;
        this.nodeTypes = nodeTypes;
        this.workflowLoaderService = workflowLoaderService;
        this.sharedWorkflowRepository = sharedWorkflowRepository;
        this.credentialsFinderService = credentialsFinderService;
    }
    async refineResourceIds(user, payload) {
        if (payload.projectId &&
            !(await (0, check_access_1.userHasScopes)(user, ['dataTable:listProject'], false, {
                projectId: payload.projectId,
            }))) {
            this.logger.warn(`Scrubbed inaccessible projectId ${payload.projectId} from DynamicNodeParameters request`);
            payload.projectId = undefined;
        }
        if (payload.workflowId) {
            const hasAccess = await (0, check_access_1.userHasScopes)(user, ['workflow:read'], false, {
                workflowId: payload.workflowId,
            });
            if (!hasAccess) {
                this.logger.warn(`Scrubbed inaccessible workflowId ${payload.workflowId} from DynamicNodeParameters request`);
                payload.workflowId = undefined;
            }
            else if (payload.projectId === undefined) {
                const project = await this.sharedWorkflowRepository.getWorkflowOwningProject(payload.workflowId);
                payload.projectId = project?.id;
            }
        }
        if (payload.credentials) {
            const credentialIds = Object.values(payload.credentials)
                .map((details) => details.id)
                .filter((id) => id !== undefined && id !== null);
            if (credentialIds.length > 0) {
                const accessibleIds = await this.credentialsFinderService.findCredentialIdsWithScopeForUser(credentialIds, user, ['credential:read']);
                const forbiddenId = credentialIds.find((id) => !accessibleIds.has(id));
                if (forbiddenId !== undefined) {
                    throw new forbidden_error_1.ForbiddenError();
                }
            }
        }
    }
    async getOptionsViaMethodName(methodName, path, additionalData, nodeTypeAndVersion, currentNodeParameters, credentials) {
        const nodeType = this.getNodeType(nodeTypeAndVersion);
        const method = this.getMethod('loadOptions', methodName, nodeType);
        const workflow = this.getWorkflow(nodeTypeAndVersion, currentNodeParameters, credentials);
        const thisArgs = this.getThisArg(path, additionalData, workflow);
        return method.call(thisArgs);
    }
    async getOptionsViaLoadOptions(loadOptions, additionalData, nodeTypeAndVersion, currentNodeParameters, credentials) {
        const nodeType = this.getNodeType(nodeTypeAndVersion);
        if (!nodeType.description.requestDefaults?.baseURL) {
            throw new n8n_workflow_1.UnexpectedError('Node type does not exist or does not have "requestDefaults.baseURL" defined!', { tags: { nodeType: nodeType.description.name } });
        }
        const mode = 'internal';
        const runIndex = 0;
        const connectionInputData = [];
        const runExecutionData = (0, n8n_workflow_1.createEmptyRunExecutionData)();
        const workflow = this.getWorkflow(nodeTypeAndVersion, currentNodeParameters, credentials);
        const node = workflow.nodes['Temp-Node'];
        const tempNodeType = {
            ...nodeType,
            ...{
                description: {
                    ...nodeType.description,
                    properties: [
                        {
                            displayName: '',
                            type: 'string',
                            name: '',
                            default: '',
                            routing: loadOptions.routing,
                        },
                    ],
                },
            },
        };
        const inputData = {
            main: [[{ json: {} }]],
        };
        const executeData = {
            node,
            source: null,
            data: {},
        };
        const executeFunctions = new n8n_core_1.ExecuteContext(workflow, node, additionalData, mode, runExecutionData, runIndex, connectionInputData, inputData, executeData, []);
        const routingNode = new n8n_core_1.RoutingNode(executeFunctions, tempNodeType);
        const optionsData = await routingNode.runNode();
        if (optionsData?.length === 0) {
            return [];
        }
        if (!Array.isArray(optionsData)) {
            throw new n8n_workflow_1.UnexpectedError('The returned data is not an array');
        }
        return optionsData[0].map((item) => item.json);
    }
    async getResourceLocatorResults(methodName, path, additionalData, nodeTypeAndVersion, currentNodeParameters, credentials, filter, paginationToken) {
        const nodeType = this.getNodeType(nodeTypeAndVersion);
        const method = this.getMethod('listSearch', methodName, nodeType);
        const workflow = this.getWorkflow(nodeTypeAndVersion, currentNodeParameters, credentials);
        const thisArgs = this.getThisArg(path, additionalData, workflow);
        return method.call(thisArgs, filter, paginationToken);
    }
    async getResourceMappingFields(methodName, path, additionalData, nodeTypeAndVersion, currentNodeParameters, credentials) {
        const nodeType = this.getNodeType(nodeTypeAndVersion);
        const method = this.getMethod('resourceMapping', methodName, nodeType);
        const workflow = this.getWorkflow(nodeTypeAndVersion, currentNodeParameters, credentials);
        const thisArgs = this.getThisArg(path, additionalData, workflow);
        return this.removeDuplicateResourceMappingFields((await method.call(thisArgs)));
    }
    async getLocalResourceMappingFields(methodName, path, additionalData, nodeTypeAndVersion) {
        const nodeType = this.getNodeType(nodeTypeAndVersion);
        const method = this.getMethod('localResourceMapping', methodName, nodeType);
        const thisArgs = this.getLocalLoadOptionsContext(path, additionalData);
        return this.removeDuplicateResourceMappingFields((await method.call(thisArgs)));
    }
    async getActionResult(handler, path, additionalData, nodeTypeAndVersion, currentNodeParameters, payload, credentials) {
        const nodeType = this.getNodeType(nodeTypeAndVersion);
        const method = this.getMethod('actionHandler', handler, nodeType);
        const workflow = this.getWorkflow(nodeTypeAndVersion, currentNodeParameters, credentials);
        const thisArgs = this.getThisArg(path, additionalData, workflow);
        return method.call(thisArgs, payload);
    }
    getMethod(type, methodName, nodeType) {
        const method = nodeType.methods?.[type]?.[methodName];
        if (typeof method !== 'function') {
            throw new n8n_workflow_1.UnexpectedError('Node type does not have method defined', {
                tags: { nodeType: nodeType.description.name },
                extra: { methodName },
            });
        }
        return method;
    }
    getNodeType({ name, version }) {
        return this.nodeTypes.getByNameAndVersion(name, version);
    }
    getWorkflow(nodeTypeAndVersion, currentNodeParameters, credentials) {
        const node = {
            parameters: currentNodeParameters,
            id: 'uuid-1234',
            name: 'Temp-Node',
            type: nodeTypeAndVersion.name,
            typeVersion: nodeTypeAndVersion.version,
            position: [0, 0],
        };
        if (credentials) {
            node.credentials = credentials;
        }
        return new n8n_workflow_1.Workflow({
            nodes: [node],
            connections: {},
            active: false,
            nodeTypes: this.nodeTypes,
        });
    }
    getThisArg(path, additionalData, workflow) {
        const node = workflow.nodes['Temp-Node'];
        return new n8n_core_1.LoadOptionsContext(workflow, node, additionalData, path);
    }
    getLocalLoadOptionsContext(path, additionalData) {
        return new n8n_core_1.LocalLoadOptionsContext(this.nodeTypes, additionalData, path, this.workflowLoaderService);
    }
    removeDuplicateResourceMappingFields(fields) {
        const uniqueFieldIds = new Set();
        return {
            ...fields,
            fields: fields.fields?.filter((field) => {
                if (uniqueFieldIds.has(field.id)) {
                    return false;
                }
                uniqueFieldIds.add(field.id);
                return true;
            }),
        };
    }
};
exports.DynamicNodeParametersService = DynamicNodeParametersService;
exports.DynamicNodeParametersService = DynamicNodeParametersService = __decorate([
    (0, di_1.Service)(),
    __metadata("design:paramtypes", [backend_common_1.Logger,
        node_types_1.NodeTypes,
        workflow_loader_service_1.WorkflowLoaderService,
        db_1.SharedWorkflowRepository,
        credentials_finder_service_1.CredentialsFinderService])
], DynamicNodeParametersService);
//# sourceMappingURL=dynamic-node-parameters.service.js.map