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 __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
import { Arg, Ctx, Field, InputType, ObjectType, Query, Mutation, Resolver } from 'type-graphql';
import { Metadata, LogError, LogStatus } from '@memberjunction/core';
import { UserCache } from '@memberjunction/sqlserver-dataprovider';
import { ComponentMetadataEngine } from '@memberjunction/core-entities';
import { ComponentRegistryClient, RegistryError, RegistryErrorCode } from '@memberjunction/component-registry-client-sdk';
import { configInfo } from '../config.js';
let ComponentSpecWithHashType = class ComponentSpecWithHashType {
    specification;
    hash;
    notModified;
    message;
};
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], ComponentSpecWithHashType.prototype, "specification", void 0);
__decorate([
    Field(() => String),
    __metadata("design:type", String)
], ComponentSpecWithHashType.prototype, "hash", void 0);
__decorate([
    Field(() => Boolean),
    __metadata("design:type", Boolean)
], ComponentSpecWithHashType.prototype, "notModified", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], ComponentSpecWithHashType.prototype, "message", void 0);
ComponentSpecWithHashType = __decorate([
    ObjectType()
], ComponentSpecWithHashType);
let SearchRegistryComponentsInput = class SearchRegistryComponentsInput {
    registryId;
    namespace;
    query;
    type;
    tags;
    limit;
    offset;
};
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], SearchRegistryComponentsInput.prototype, "registryId", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], SearchRegistryComponentsInput.prototype, "namespace", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], SearchRegistryComponentsInput.prototype, "query", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], SearchRegistryComponentsInput.prototype, "type", void 0);
__decorate([
    Field(() => [String], { nullable: true }),
    __metadata("design:type", Array)
], SearchRegistryComponentsInput.prototype, "tags", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", Number)
], SearchRegistryComponentsInput.prototype, "limit", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", Number)
], SearchRegistryComponentsInput.prototype, "offset", void 0);
SearchRegistryComponentsInput = __decorate([
    InputType()
], SearchRegistryComponentsInput);
let RegistryComponentSearchResultType = class RegistryComponentSearchResultType {
    components;
    total;
    offset;
    limit;
};
__decorate([
    Field(() => [String]),
    __metadata("design:type", Array)
], RegistryComponentSearchResultType.prototype, "components", void 0);
__decorate([
    Field(),
    __metadata("design:type", Number)
], RegistryComponentSearchResultType.prototype, "total", void 0);
__decorate([
    Field(),
    __metadata("design:type", Number)
], RegistryComponentSearchResultType.prototype, "offset", void 0);
__decorate([
    Field(),
    __metadata("design:type", Number)
], RegistryComponentSearchResultType.prototype, "limit", void 0);
RegistryComponentSearchResultType = __decorate([
    ObjectType()
], RegistryComponentSearchResultType);
let ComponentDependencyTreeType = class ComponentDependencyTreeType {
    componentId;
    name;
    namespace;
    version;
    circular;
    totalCount;
    dependencies;
};
__decorate([
    Field(),
    __metadata("design:type", String)
], ComponentDependencyTreeType.prototype, "componentId", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], ComponentDependencyTreeType.prototype, "name", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], ComponentDependencyTreeType.prototype, "namespace", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], ComponentDependencyTreeType.prototype, "version", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", Boolean)
], ComponentDependencyTreeType.prototype, "circular", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", Number)
], ComponentDependencyTreeType.prototype, "totalCount", void 0);
__decorate([
    Field(() => [ComponentDependencyTreeType], { nullable: true }),
    __metadata("design:type", Array)
], ComponentDependencyTreeType.prototype, "dependencies", void 0);
ComponentDependencyTreeType = __decorate([
    ObjectType()
], ComponentDependencyTreeType);
let ComponentFeedbackInput = class ComponentFeedbackInput {
    componentName;
    componentNamespace;
    componentVersion;
    registryName;
    rating;
    feedbackType;
    comments;
    conversationID;
    conversationDetailID;
    reportID;
    dashboardID;
};
__decorate([
    Field(),
    __metadata("design:type", String)
], ComponentFeedbackInput.prototype, "componentName", void 0);
__decorate([
    Field(),
    __metadata("design:type", String)
], ComponentFeedbackInput.prototype, "componentNamespace", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], ComponentFeedbackInput.prototype, "componentVersion", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], ComponentFeedbackInput.prototype, "registryName", void 0);
__decorate([
    Field(),
    __metadata("design:type", Number)
], ComponentFeedbackInput.prototype, "rating", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], ComponentFeedbackInput.prototype, "feedbackType", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], ComponentFeedbackInput.prototype, "comments", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], ComponentFeedbackInput.prototype, "conversationID", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], ComponentFeedbackInput.prototype, "conversationDetailID", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], ComponentFeedbackInput.prototype, "reportID", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], ComponentFeedbackInput.prototype, "dashboardID", void 0);
ComponentFeedbackInput = __decorate([
    InputType()
], ComponentFeedbackInput);
let ComponentFeedbackResponse = class ComponentFeedbackResponse {
    success;
    feedbackID;
    error;
};
__decorate([
    Field(),
    __metadata("design:type", Boolean)
], ComponentFeedbackResponse.prototype, "success", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], ComponentFeedbackResponse.prototype, "feedbackID", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], ComponentFeedbackResponse.prototype, "error", void 0);
ComponentFeedbackResponse = __decorate([
    ObjectType()
], ComponentFeedbackResponse);
let ComponentRegistryExtendedResolver = class ComponentRegistryExtendedResolver {
    componentEngine = ComponentMetadataEngine.Instance;
    constructor() {
    }
    async GetRegistryComponent(registryName, namespace, name, { userPayload }, version, hash) {
        try {
            const user = UserCache.Instance.Users.find((u) => u.Email.trim().toLowerCase() === userPayload.email?.trim().toLowerCase());
            if (!user)
                throw new Error(`User ${userPayload.email} not found in UserCache`);
            const registry = await this.getRegistryByName(registryName, user);
            if (!registry) {
                throw new Error(`Registry not found: ${registryName}`);
            }
            await this.checkUserAccess(user, registry.ID);
            await this.componentEngine.Config(false, user);
            const registryClient = this.createClientForRegistry(registry);
            const response = await registryClient.getComponentWithHash({
                registry: registry.Name,
                namespace,
                name,
                version: version || 'latest',
                hash: hash,
                userEmail: user.Email
            });
            if (response.notModified) {
                LogStatus(`Component ${namespace}/${name} not modified (hash: ${response.hash})`);
                return {
                    specification: undefined,
                    hash: response.hash,
                    notModified: true,
                    message: response.message || 'Not modified'
                };
            }
            const component = response.specification;
            if (!component) {
                throw new Error(`Component ${namespace}/${name} returned without specification`);
            }
            if (this.shouldCache(registry)) {
                await this.cacheComponent(component, registry.ID, user);
            }
            return {
                specification: JSON.stringify(component),
                hash: response.hash,
                notModified: false,
                message: undefined
            };
        }
        catch (error) {
            if (error instanceof RegistryError) {
                LogError(`Registry error [${error.code}]: ${error.message}`);
                if (error.code === RegistryErrorCode.COMPONENT_NOT_FOUND) {
                    return {
                        specification: undefined,
                        hash: '',
                        notModified: false,
                        message: 'Component not found'
                    };
                }
            }
            LogError(error);
            throw error;
        }
    }
    async SearchRegistryComponents(params, { userPayload }) {
        try {
            const user = UserCache.Instance.Users.find((u) => u.Email.trim().toLowerCase() === userPayload.email?.trim().toLowerCase());
            if (!user)
                throw new Error(`User ${userPayload.email} not found in UserCache`);
            if (params.registryId) {
                await this.checkUserAccess(user, params.registryId);
                const registry = await this.getRegistry(params.registryId, user);
                if (!registry) {
                    throw new Error(`Registry not found: ${params.registryId}`);
                }
                const client = this.createClientForRegistry(registry);
                const result = await client.searchComponents({
                    namespace: params.namespace,
                    query: params.query,
                    type: params.type,
                    tags: params.tags,
                    limit: params.limit || 10,
                    offset: params.offset || 0
                });
                return this.mapSearchResult(result);
            }
            const allResults = [];
            await this.componentEngine.Config(false, user);
            const activeRegistries = this.componentEngine.ComponentRegistries?.filter(r => r.Status === 'Active') || [];
            for (const registry of activeRegistries) {
                try {
                    await this.checkUserAccess(user, registry.ID);
                    const client = this.createClientForRegistry(registry);
                    const result = await client.searchComponents({
                        namespace: params.namespace,
                        query: params.query,
                        type: params.type,
                        tags: params.tags,
                        limit: params.limit || 10,
                        offset: 0
                    });
                    allResults.push(...result.components);
                }
                catch (error) {
                    LogError(`Failed to search registry ${registry.Name}: ${error}`);
                }
            }
            const offset = params.offset || 0;
            const limit = params.limit || 10;
            const paginatedResults = allResults.slice(offset, offset + limit);
            return {
                components: paginatedResults.map(spec => JSON.stringify(spec)),
                total: allResults.length,
                offset,
                limit
            };
        }
        catch (error) {
            LogError(error);
            throw error;
        }
    }
    async ResolveComponentDependencies(registryName, componentId, { userPayload }) {
        try {
            const user = UserCache.Instance.Users.find((u) => u.Email.trim().toLowerCase() === userPayload.email?.trim().toLowerCase());
            if (!user)
                throw new Error(`User ${userPayload.email} not found in UserCache`);
            const registry = await this.getRegistryByName(registryName, user);
            if (!registry) {
                throw new Error(`Registry not found: ${registryName}`);
            }
            await this.checkUserAccess(user, registry.ID);
            const client = this.createClientForRegistry(registry);
            const tree = await client.resolveDependencies(componentId);
            return tree;
        }
        catch (error) {
            LogError(error);
            throw error;
        }
    }
    async checkUserAccess(userInfo, registryId) {
        if (!userInfo) {
            throw new Error('User must be authenticated to access component registries');
        }
    }
    async getRegistry(registryId, userInfo) {
        try {
            await this.componentEngine.Config(false, userInfo);
            const registry = this.componentEngine.ComponentRegistries?.find(r => r.ID === registryId);
            return registry || null;
        }
        catch (error) {
            LogError(error);
            return null;
        }
    }
    async getRegistryByName(registryName, userInfo) {
        try {
            await this.componentEngine.Config(false, userInfo);
            const registry = this.componentEngine.ComponentRegistries?.find(r => r.Name === registryName && r.Status === 'Active');
            return registry || null;
        }
        catch (error) {
            LogError(error);
            return null;
        }
    }
    getRegistryUri(registry) {
        if (!registry.Name) {
            return registry.URI || '';
        }
        const envVarName = `REGISTRY_URI_OVERRIDE_${registry.Name.replace(/[^A-Za-z0-9]/g, '_').toUpperCase()}`;
        const override = process.env[envVarName];
        if (override) {
            LogStatus(`Using URI override for registry ${registry.Name}: ${override}`);
            return override;
        }
        return registry.URI || '';
    }
    createClientForRegistry(registry) {
        const config = configInfo.componentRegistries?.find(r => r.id === registry.ID || r.name === registry.Name);
        const apiKey = process.env[`REGISTRY_API_KEY_${registry.ID.replace(/-/g, '_').toUpperCase()}`] ||
            process.env[`REGISTRY_API_KEY_${registry.Name?.replace(/-/g, '_').toUpperCase()}`] ||
            config?.apiKey;
        const baseUrl = this.getRegistryUri(registry);
        const retryPolicy = {
            maxRetries: config?.retryPolicy?.maxRetries ?? 3,
            initialDelay: config?.retryPolicy?.initialDelay ?? 1000,
            maxDelay: config?.retryPolicy?.maxDelay ?? 10000,
            backoffMultiplier: config?.retryPolicy?.backoffMultiplier ?? 2
        };
        return new ComponentRegistryClient({
            baseUrl: baseUrl,
            apiKey: apiKey,
            timeout: config?.timeout || 30000,
            retryPolicy: retryPolicy,
            headers: config?.headers
        });
    }
    shouldCache(registry) {
        const config = configInfo.componentRegistries?.find(r => r.id === registry.ID || r.name === registry.Name);
        return config?.cache !== false;
    }
    async cacheComponent(component, registryId, userInfo) {
        try {
            const md = new Metadata();
            const componentEntity = await md.GetEntityObject('MJ: Components', userInfo);
            const existingComponent = this.componentEngine.Components?.find(c => c.Name === component.name &&
                c.Namespace === component.namespace &&
                c.SourceRegistryID === registryId);
            if (existingComponent) {
                if (!await componentEntity.Load(existingComponent.ID)) {
                    throw new Error(`Failed to load component: ${existingComponent.ID}`);
                }
            }
            else {
                componentEntity.NewRecord();
                componentEntity.SourceRegistryID = registryId;
            }
            componentEntity.Name = component.name;
            componentEntity.Namespace = component.namespace || '';
            componentEntity.Version = component.version || '1.0.0';
            componentEntity.Title = component.title;
            componentEntity.Description = component.description;
            componentEntity.Type = this.mapComponentType(component.type);
            componentEntity.FunctionalRequirements = component.functionalRequirements;
            componentEntity.TechnicalDesign = component.technicalDesign;
            componentEntity.Specification = JSON.stringify(component);
            componentEntity.LastSyncedAt = new Date();
            if (!existingComponent) {
                componentEntity.ReplicatedAt = new Date();
            }
            const result = await componentEntity.Save();
            if (!result) {
                throw new Error(`Failed to cache component: ${component.name}`);
            }
            await this.componentEngine.Config(true, userInfo);
        }
        catch (error) {
            LogError('Failed to cache component:');
        }
    }
    mapComponentType(type) {
        const typeMap = {
            'report': 'Report',
            'dashboard': 'Dashboard',
            'form': 'Form',
            'table': 'Table',
            'chart': 'Chart',
            'navigation': 'Navigation',
            'search': 'Search',
            'widget': 'Widget',
            'utility': 'Utility',
            'other': 'Other'
        };
        return typeMap[type.toLowerCase()] || 'Other';
    }
    mapSearchResult(result) {
        return {
            components: result.components.map(spec => JSON.stringify(spec)),
            total: result.total,
            offset: result.offset,
            limit: result.limit
        };
    }
    async SendComponentFeedback(feedback, { userPayload }) {
        try {
            const user = UserCache.Instance.Users.find((u) => u.Email.trim().toLowerCase() === userPayload.email?.trim().toLowerCase());
            if (!user) {
                return {
                    success: false,
                    error: `User ${userPayload.email} not found in UserCache`
                };
            }
            if (!feedback.registryName) {
                return {
                    success: false,
                    error: 'Registry name is required for feedback submission'
                };
            }
            const registry = await this.getRegistryByName(feedback.registryName, user);
            if (!registry) {
                return {
                    success: false,
                    error: `Registry not found: ${feedback.registryName}`
                };
            }
            await this.checkUserAccess(user, registry.ID);
            const registryClient = this.createClientForRegistry(registry);
            const sdkParams = {
                componentName: feedback.componentName,
                componentNamespace: feedback.componentNamespace,
                componentVersion: feedback.componentVersion,
                registryName: feedback.registryName,
                rating: feedback.rating,
                feedbackType: feedback.feedbackType,
                comments: feedback.comments,
                conversationID: feedback.conversationID,
                conversationDetailID: feedback.conversationDetailID,
                reportID: feedback.reportID,
                dashboardID: feedback.dashboardID,
                userEmail: user.Email
            };
            const result = await registryClient.submitFeedback(sdkParams);
            return result;
        }
        catch (error) {
            LogError(error);
            return {
                success: false,
                error: error instanceof Error ? error.message : 'Unknown error'
            };
        }
    }
};
__decorate([
    Query(() => ComponentSpecWithHashType),
    __param(0, Arg('registryName')),
    __param(1, Arg('namespace')),
    __param(2, Arg('name')),
    __param(3, Ctx()),
    __param(4, Arg('version', { nullable: true })),
    __param(5, Arg('hash', { nullable: true })),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, String, String, Object, String, String]),
    __metadata("design:returntype", Promise)
], ComponentRegistryExtendedResolver.prototype, "GetRegistryComponent", null);
__decorate([
    Query(() => RegistryComponentSearchResultType),
    __param(0, Arg('params')),
    __param(1, Ctx()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [SearchRegistryComponentsInput, Object]),
    __metadata("design:returntype", Promise)
], ComponentRegistryExtendedResolver.prototype, "SearchRegistryComponents", null);
__decorate([
    Query(() => ComponentDependencyTreeType, { nullable: true }),
    __param(0, Arg('registryName')),
    __param(1, Arg('componentId')),
    __param(2, Ctx()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, String, Object]),
    __metadata("design:returntype", Promise)
], ComponentRegistryExtendedResolver.prototype, "ResolveComponentDependencies", null);
__decorate([
    Mutation(() => ComponentFeedbackResponse),
    __param(0, Arg('feedback')),
    __param(1, Ctx()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [ComponentFeedbackInput, Object]),
    __metadata("design:returntype", Promise)
], ComponentRegistryExtendedResolver.prototype, "SendComponentFeedback", null);
ComponentRegistryExtendedResolver = __decorate([
    Resolver(),
    __metadata("design:paramtypes", [])
], ComponentRegistryExtendedResolver);
export { ComponentRegistryExtendedResolver };
//# sourceMappingURL=ComponentRegistryResolver.js.map