"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);
};
var InstanceAiSettingsService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.InstanceAiSettingsService = void 0;
const config_1 = require("@n8n/config");
const db_1 = require("@n8n/db");
const di_1 = require("@n8n/di");
const api_types_1 = require("@n8n/api-types");
const n8n_workflow_1 = require("n8n-workflow");
const ai_service_1 = require("../../services/ai.service");
const credentials_finder_service_1 = require("../../credentials/credentials-finder.service");
const credentials_service_1 = require("../../credentials/credentials.service");
const unprocessable_error_1 = require("../../errors/response-errors/unprocessable.error");
const ADMIN_SETTINGS_KEY = 'instanceAi.settings';
const USER_PREFERENCES_KEY_PREFIX = 'instanceAi.preferences.';
const CREDENTIAL_TO_MASTRA_PROVIDER = {
    openAiApi: 'openai',
    anthropicApi: 'anthropic',
    googlePalmApi: 'google',
    ollamaApi: 'ollama',
    groqApi: 'groq',
    deepSeekApi: 'deepseek',
    mistralCloudApi: 'mistral',
    xAiApi: 'xai',
    openRouterApi: 'openrouter',
    cohereApi: 'cohere',
};
const SUPPORTED_CREDENTIAL_TYPES = Object.keys(CREDENTIAL_TO_MASTRA_PROVIDER);
const URL_FIELD_MAP = {
    openAiApi: 'url',
    anthropicApi: 'url',
    googlePalmApi: 'host',
    ollamaApi: 'baseUrl',
};
const SANDBOX_CREDENTIAL_TYPES = ['daytonaApi', 'httpHeaderAuth'];
const SEARCH_CREDENTIAL_TYPES = ['braveSearchApi', 'searXngApi'];
const SERVICE_CREDENTIAL_TYPES = [...SANDBOX_CREDENTIAL_TYPES, ...SEARCH_CREDENTIAL_TYPES];
let InstanceAiSettingsService = InstanceAiSettingsService_1 = class InstanceAiSettingsService {
    constructor(globalConfig, settingsRepository, aiService, credentialsService, credentialsFinderService) {
        this.settingsRepository = settingsRepository;
        this.aiService = aiService;
        this.credentialsService = credentialsService;
        this.credentialsFinderService = credentialsFinderService;
        this.enabled = true;
        this.permissions = { ...api_types_1.DEFAULT_INSTANCE_AI_PERMISSIONS };
        this.adminDaytonaCredentialId = null;
        this.adminN8nSandboxCredentialId = null;
        this.adminSearchCredentialId = null;
        this.optinModalDismissed = false;
        this.userPreferences = new Map();
        this.config = globalConfig.instanceAi;
    }
    isProxyEnabled() {
        return this.aiService.isProxyEnabled();
    }
    async loadFromDb() {
        const row = await this.settingsRepository.findByKey(ADMIN_SETTINGS_KEY);
        if (row) {
            const persisted = (0, n8n_workflow_1.jsonParse)(row.value, {
                fallbackValue: {},
            });
            this.applyAdminSettings(persisted);
        }
    }
    getAdminSettings() {
        const c = this.config;
        return {
            enabled: this.enabled,
            lastMessages: c.lastMessages,
            embedderModel: c.embedderModel,
            semanticRecallTopK: c.semanticRecallTopK,
            subAgentMaxSteps: c.subAgentMaxSteps,
            browserMcp: c.browserMcp,
            permissions: { ...this.permissions },
            mcpServers: c.mcpServers,
            sandboxEnabled: c.sandboxEnabled,
            sandboxProvider: c.sandboxProvider,
            sandboxImage: c.sandboxImage,
            sandboxTimeout: c.sandboxTimeout,
            daytonaCredentialId: this.adminDaytonaCredentialId,
            n8nSandboxCredentialId: this.adminN8nSandboxCredentialId,
            searchCredentialId: this.adminSearchCredentialId,
            localGatewayDisabled: this.isLocalGatewayDisabled(),
            optinModalDismissed: this.optinModalDismissed,
        };
    }
    async updateAdminSettings(update) {
        if (this.aiService.isProxyEnabled()) {
            this.rejectProxyManagedFields(update, InstanceAiSettingsService_1.PROXY_MANAGED_ADMIN_FIELDS);
        }
        const c = this.config;
        if (update.enabled !== undefined)
            this.enabled = update.enabled;
        if (update.lastMessages !== undefined)
            c.lastMessages = update.lastMessages;
        if (update.embedderModel !== undefined)
            c.embedderModel = update.embedderModel;
        if (update.semanticRecallTopK !== undefined)
            c.semanticRecallTopK = update.semanticRecallTopK;
        if (update.subAgentMaxSteps !== undefined)
            c.subAgentMaxSteps = update.subAgentMaxSteps;
        if (update.browserMcp !== undefined)
            c.browserMcp = update.browserMcp;
        if (update.permissions) {
            this.permissions = { ...this.permissions, ...update.permissions };
        }
        if (update.mcpServers !== undefined)
            c.mcpServers = update.mcpServers;
        if (update.sandboxEnabled !== undefined)
            c.sandboxEnabled = update.sandboxEnabled;
        if (update.sandboxProvider !== undefined)
            c.sandboxProvider = update.sandboxProvider;
        if (update.sandboxImage !== undefined)
            c.sandboxImage = update.sandboxImage;
        if (update.sandboxTimeout !== undefined)
            c.sandboxTimeout = update.sandboxTimeout;
        if (update.daytonaCredentialId !== undefined)
            this.adminDaytonaCredentialId = update.daytonaCredentialId;
        if (update.n8nSandboxCredentialId !== undefined)
            this.adminN8nSandboxCredentialId = update.n8nSandboxCredentialId;
        if (update.searchCredentialId !== undefined)
            this.adminSearchCredentialId = update.searchCredentialId;
        if (update.localGatewayDisabled !== undefined)
            c.localGatewayDisabled = update.localGatewayDisabled;
        if (update.optinModalDismissed !== undefined)
            this.optinModalDismissed = update.optinModalDismissed;
        await this.persistAdminSettings();
        return this.getAdminSettings();
    }
    async getUserPreferences(user) {
        const prefs = await this.loadUserPreferences(user.id);
        const credentialId = prefs.credentialId ?? null;
        let credentialType = null;
        let credentialName = null;
        if (credentialId) {
            const cred = await this.credentialsFinderService.findCredentialForUser(credentialId, user, [
                'credential:read',
            ]);
            if (cred) {
                credentialType = cred.type;
                credentialName = cred.name;
            }
        }
        return {
            credentialId,
            credentialType,
            credentialName,
            modelName: prefs.modelName || this.extractModelName(this.config.model),
            localGatewayDisabled: this.config.localGatewayDisabled || (prefs.localGatewayDisabled ?? false),
        };
    }
    async updateUserPreferences(user, update) {
        if (this.aiService.isProxyEnabled()) {
            this.rejectProxyManagedFields(update, InstanceAiSettingsService_1.PROXY_MANAGED_PREFERENCE_FIELDS);
        }
        const prefs = await this.loadUserPreferences(user.id);
        if (update.credentialId !== undefined)
            prefs.credentialId = update.credentialId;
        if (update.modelName !== undefined)
            prefs.modelName = update.modelName;
        if (update.localGatewayDisabled !== undefined)
            prefs.localGatewayDisabled = update.localGatewayDisabled;
        this.userPreferences.set(user.id, prefs);
        await this.persistUserPreferences(user.id, prefs);
        return await this.getUserPreferences(user);
    }
    async listModelCredentials(user) {
        if (this.aiService.isProxyEnabled())
            return [];
        const allCredentials = await this.credentialsFinderService.findCredentialsForUser(user, [
            'credential:read',
        ]);
        return allCredentials
            .filter((c) => SUPPORTED_CREDENTIAL_TYPES.includes(c.type))
            .map((c) => ({
            id: c.id,
            name: c.name,
            type: c.type,
            provider: CREDENTIAL_TO_MASTRA_PROVIDER[c.type] ?? 'custom',
        }));
    }
    async listServiceCredentials(user) {
        if (this.aiService.isProxyEnabled())
            return [];
        const allCredentials = await this.credentialsFinderService.findCredentialsForUser(user, [
            'credential:read',
        ]);
        return allCredentials
            .filter((c) => SERVICE_CREDENTIAL_TYPES.includes(c.type))
            .map((c) => ({
            id: c.id,
            name: c.name,
            type: c.type,
            provider: c.type,
        }));
    }
    async resolveDaytonaConfig(user) {
        const credentialId = this.adminDaytonaCredentialId;
        if (!credentialId) {
            const { daytonaApiUrl, daytonaApiKey } = this.config;
            return {
                apiUrl: daytonaApiUrl || undefined,
                apiKey: daytonaApiKey || undefined,
            };
        }
        const credential = await this.credentialsFinderService.findCredentialForUser(credentialId, user, ['credential:read']);
        if (!credential) {
            return {};
        }
        const data = this.credentialsService.decrypt(credential, true);
        return {
            apiUrl: typeof data.apiUrl === 'string' ? data.apiUrl : undefined,
            apiKey: typeof data.apiKey === 'string' ? data.apiKey : undefined,
        };
    }
    async resolveN8nSandboxConfig(user) {
        const { n8nSandboxServiceUrl, n8nSandboxServiceApiKey } = this.config;
        const credentialId = this.adminN8nSandboxCredentialId;
        if (!credentialId) {
            return {
                serviceUrl: n8nSandboxServiceUrl || undefined,
                apiKey: n8nSandboxServiceApiKey || undefined,
            };
        }
        const credential = await this.credentialsFinderService.findCredentialForUser(credentialId, user, ['credential:read']);
        if (!credential) {
            return {
                serviceUrl: n8nSandboxServiceUrl || undefined,
                apiKey: n8nSandboxServiceApiKey || undefined,
            };
        }
        const data = this.credentialsService.decrypt(credential, true);
        const headerName = typeof data.name === 'string' ? data.name.trim().toLowerCase() : '';
        const apiKey = typeof data.value === 'string' ? data.value : undefined;
        return {
            serviceUrl: n8nSandboxServiceUrl || undefined,
            apiKey: headerName === 'x-api-key' ? apiKey : n8nSandboxServiceApiKey || undefined,
        };
    }
    async resolveSearchConfig(user) {
        const credentialId = this.adminSearchCredentialId;
        if (!credentialId) {
            const { braveSearchApiKey, searxngUrl } = this.config;
            return {
                braveApiKey: braveSearchApiKey || undefined,
                searxngUrl: searxngUrl || undefined,
            };
        }
        const credential = await this.credentialsFinderService.findCredentialForUser(credentialId, user, ['credential:read']);
        if (!credential) {
            return {};
        }
        const data = this.credentialsService.decrypt(credential, true);
        if (credential.type === 'braveSearchApi') {
            return { braveApiKey: typeof data.apiKey === 'string' ? data.apiKey : undefined };
        }
        if (credential.type === 'searXngApi') {
            return { searxngUrl: typeof data.apiUrl === 'string' ? data.apiUrl : undefined };
        }
        return {};
    }
    getPermissions() {
        return { ...this.permissions };
    }
    isLocalGatewayDisabledForUser(userId) {
        if (this.config.localGatewayDisabled)
            return true;
        const prefs = this.userPreferences.get(userId);
        return prefs?.localGatewayDisabled ?? false;
    }
    isAgentEnabled() {
        return this.enabled;
    }
    isLocalGatewayDisabled() {
        return this.config.localGatewayDisabled;
    }
    isInstanceAiEnabled() {
        return this.enabled;
    }
    async resolveModelName(user) {
        const prefs = await this.loadUserPreferences(user.id);
        return prefs.modelName || this.extractModelName(this.config.model);
    }
    async resolveModelConfig(user) {
        const prefs = await this.loadUserPreferences(user.id);
        const credentialId = prefs.credentialId ?? null;
        if (!credentialId) {
            return this.envVarModelConfig();
        }
        const credential = await this.credentialsFinderService.findCredentialForUser(credentialId, user, ['credential:read']);
        if (!credential) {
            return this.envVarModelConfig();
        }
        const provider = CREDENTIAL_TO_MASTRA_PROVIDER[credential.type];
        if (!provider) {
            return this.envVarModelConfig();
        }
        const data = this.credentialsService.decrypt(credential, true);
        const apiKey = typeof data.apiKey === 'string' ? data.apiKey : '';
        const urlField = URL_FIELD_MAP[credential.type];
        const rawUrl = urlField ? data[urlField] : undefined;
        const baseUrl = typeof rawUrl === 'string' ? rawUrl : '';
        const modelName = prefs.modelName || this.extractModelName(this.config.model);
        const id = `${provider}/${modelName}`;
        if (baseUrl) {
            return { id, url: baseUrl, ...(apiKey ? { apiKey } : {}) };
        }
        if (apiKey) {
            return { id, url: '', apiKey };
        }
        return id;
    }
    rejectProxyManagedFields(update, managedFields) {
        const present = managedFields.filter((key) => key in update && update[key] !== undefined);
        if (present.length > 0) {
            throw new unprocessable_error_1.UnprocessableRequestError(`Cannot update proxy-managed fields: ${present.join(', ')}`);
        }
    }
    envVarModelConfig() {
        const { model, modelUrl, modelApiKey } = this.config;
        const id = model.includes('/')
            ? model
            : `custom/${model}`;
        if (modelUrl) {
            return { id, url: modelUrl, ...(modelApiKey ? { apiKey: modelApiKey } : {}) };
        }
        if (modelApiKey) {
            return { id, url: '', apiKey: modelApiKey };
        }
        return model;
    }
    extractModelName(model) {
        const slash = model.indexOf('/');
        return slash >= 0 ? model.slice(slash + 1) : model;
    }
    applyAdminSettings(persisted) {
        const c = this.config;
        if (persisted.enabled !== undefined)
            this.enabled = persisted.enabled;
        if (persisted.lastMessages !== undefined)
            c.lastMessages = persisted.lastMessages;
        if (persisted.embedderModel !== undefined)
            c.embedderModel = persisted.embedderModel;
        if (persisted.semanticRecallTopK !== undefined)
            c.semanticRecallTopK = persisted.semanticRecallTopK;
        if (persisted.subAgentMaxSteps !== undefined)
            c.subAgentMaxSteps = persisted.subAgentMaxSteps;
        if (persisted.browserMcp !== undefined)
            c.browserMcp = persisted.browserMcp;
        if (persisted.permissions) {
            this.permissions = {
                ...api_types_1.DEFAULT_INSTANCE_AI_PERMISSIONS,
                ...persisted.permissions,
            };
        }
        if (persisted.mcpServers !== undefined)
            c.mcpServers = persisted.mcpServers;
        if (persisted.sandboxEnabled !== undefined)
            c.sandboxEnabled = persisted.sandboxEnabled;
        if (persisted.sandboxProvider !== undefined)
            c.sandboxProvider = persisted.sandboxProvider;
        if (persisted.sandboxImage !== undefined)
            c.sandboxImage = persisted.sandboxImage;
        if (persisted.sandboxTimeout !== undefined)
            c.sandboxTimeout = persisted.sandboxTimeout;
        if (persisted.daytonaCredentialId !== undefined)
            this.adminDaytonaCredentialId = persisted.daytonaCredentialId;
        if (persisted.n8nSandboxCredentialId !== undefined)
            this.adminN8nSandboxCredentialId = persisted.n8nSandboxCredentialId;
        if (persisted.searchCredentialId !== undefined)
            this.adminSearchCredentialId = persisted.searchCredentialId;
        if (persisted.localGatewayDisabled !== undefined)
            c.localGatewayDisabled = persisted.localGatewayDisabled;
        if (persisted.optinModalDismissed !== undefined)
            this.optinModalDismissed = persisted.optinModalDismissed;
    }
    async loadUserPreferences(userId) {
        const cached = this.userPreferences.get(userId);
        if (cached)
            return { ...cached };
        const row = await this.settingsRepository.findByKey(`${USER_PREFERENCES_KEY_PREFIX}${userId}`);
        if (row) {
            const prefs = (0, n8n_workflow_1.jsonParse)(row.value, { fallbackValue: {} });
            this.userPreferences.set(userId, prefs);
            return { ...prefs };
        }
        return {};
    }
    async persistAdminSettings() {
        const c = this.config;
        const value = {
            enabled: this.enabled,
            lastMessages: c.lastMessages,
            embedderModel: c.embedderModel,
            semanticRecallTopK: c.semanticRecallTopK,
            subAgentMaxSteps: c.subAgentMaxSteps,
            browserMcp: c.browserMcp,
            permissions: this.permissions,
            mcpServers: c.mcpServers,
            sandboxEnabled: c.sandboxEnabled,
            sandboxProvider: c.sandboxProvider,
            sandboxImage: c.sandboxImage,
            sandboxTimeout: c.sandboxTimeout,
            daytonaCredentialId: this.adminDaytonaCredentialId,
            n8nSandboxCredentialId: this.adminN8nSandboxCredentialId,
            searchCredentialId: this.adminSearchCredentialId,
            localGatewayDisabled: c.localGatewayDisabled,
            optinModalDismissed: this.optinModalDismissed,
        };
        await this.settingsRepository.upsert({ key: ADMIN_SETTINGS_KEY, value: JSON.stringify(value), loadOnStartup: true }, ['key']);
    }
    async persistUserPreferences(userId, prefs) {
        await this.settingsRepository.upsert({
            key: `${USER_PREFERENCES_KEY_PREFIX}${userId}`,
            value: JSON.stringify(prefs),
            loadOnStartup: false,
        }, ['key']);
    }
};
exports.InstanceAiSettingsService = InstanceAiSettingsService;
InstanceAiSettingsService.PROXY_MANAGED_ADMIN_FIELDS = [
    'sandboxEnabled',
    'sandboxProvider',
    'sandboxImage',
    'sandboxTimeout',
    'daytonaCredentialId',
    'searchCredentialId',
];
InstanceAiSettingsService.PROXY_MANAGED_PREFERENCE_FIELDS = [
    'credentialId',
    'modelName',
];
exports.InstanceAiSettingsService = InstanceAiSettingsService = InstanceAiSettingsService_1 = __decorate([
    (0, di_1.Service)(),
    __metadata("design:paramtypes", [config_1.GlobalConfig,
        db_1.SettingsRepository,
        ai_service_1.AiService,
        credentials_service_1.CredentialsService,
        credentials_finder_service_1.CredentialsFinderService])
], InstanceAiSettingsService);
//# sourceMappingURL=instance-ai-settings.service.js.map