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, Mutation, ObjectType, registerEnumType, Resolver, PubSub, PubSubEngine } from 'type-graphql';
import { LogError, RunView, CompositeKey, LogStatus } from '@memberjunction/core';
import { RequireSystemUser } from '../directives/RequireSystemUser.js';
import { MJQueryResolver, MJQuery_ } from '../generated/generated.js';
import { GetReadWriteProvider } from '../util.js';
import { DeleteOptionsInput } from '../generic/DeleteOptionsInput.js';
/**
 * Query status enumeration for GraphQL
 */
export var QueryStatus;
(function (QueryStatus) {
    QueryStatus["Pending"] = "Pending";
    QueryStatus["Approved"] = "Approved";
    QueryStatus["Rejected"] = "Rejected";
    QueryStatus["Expired"] = "Expired";
})(QueryStatus || (QueryStatus = {}));
registerEnumType(QueryStatus, {
    name: "QueryStatus",
    description: "Status of a query: Pending, Approved, Rejected, or Expired"
});
let QueryPermissionInputType = class QueryPermissionInputType {
};
__decorate([
    Field(() => String),
    __metadata("design:type", String)
], QueryPermissionInputType.prototype, "RoleID", void 0);
QueryPermissionInputType = __decorate([
    InputType()
], QueryPermissionInputType);
export { QueryPermissionInputType };
let CreateQuerySystemUserInput = class CreateQuerySystemUserInput {
};
__decorate([
    Field(() => String),
    __metadata("design:type", String)
], CreateQuerySystemUserInput.prototype, "Name", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], CreateQuerySystemUserInput.prototype, "CategoryID", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], CreateQuerySystemUserInput.prototype, "CategoryPath", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], CreateQuerySystemUserInput.prototype, "UserQuestion", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], CreateQuerySystemUserInput.prototype, "Description", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], CreateQuerySystemUserInput.prototype, "SQL", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], CreateQuerySystemUserInput.prototype, "TechnicalDescription", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], CreateQuerySystemUserInput.prototype, "OriginalSQL", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], CreateQuerySystemUserInput.prototype, "Feedback", void 0);
__decorate([
    Field(() => QueryStatus, { nullable: true, defaultValue: QueryStatus.Pending }),
    __metadata("design:type", String)
], CreateQuerySystemUserInput.prototype, "Status", void 0);
__decorate([
    Field(() => Number, { nullable: true }),
    __metadata("design:type", Number)
], CreateQuerySystemUserInput.prototype, "QualityRank", void 0);
__decorate([
    Field(() => Number, { nullable: true }),
    __metadata("design:type", Number)
], CreateQuerySystemUserInput.prototype, "ExecutionCostRank", void 0);
__decorate([
    Field(() => Boolean, { nullable: true }),
    __metadata("design:type", Boolean)
], CreateQuerySystemUserInput.prototype, "UsesTemplate", void 0);
__decorate([
    Field(() => Boolean, { nullable: true }),
    __metadata("design:type", Boolean)
], CreateQuerySystemUserInput.prototype, "AuditQueryRuns", void 0);
__decorate([
    Field(() => Boolean, { nullable: true }),
    __metadata("design:type", Boolean)
], CreateQuerySystemUserInput.prototype, "CacheEnabled", void 0);
__decorate([
    Field(() => Number, { nullable: true }),
    __metadata("design:type", Number)
], CreateQuerySystemUserInput.prototype, "CacheTTLMinutes", void 0);
__decorate([
    Field(() => Number, { nullable: true }),
    __metadata("design:type", Number)
], CreateQuerySystemUserInput.prototype, "CacheMaxSize", void 0);
__decorate([
    Field(() => [QueryPermissionInputType], { nullable: true }),
    __metadata("design:type", Array)
], CreateQuerySystemUserInput.prototype, "Permissions", void 0);
CreateQuerySystemUserInput = __decorate([
    InputType()
], CreateQuerySystemUserInput);
export { CreateQuerySystemUserInput };
let UpdateQuerySystemUserInput = class UpdateQuerySystemUserInput {
};
__decorate([
    Field(() => String),
    __metadata("design:type", String)
], UpdateQuerySystemUserInput.prototype, "ID", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], UpdateQuerySystemUserInput.prototype, "Name", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], UpdateQuerySystemUserInput.prototype, "CategoryID", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], UpdateQuerySystemUserInput.prototype, "CategoryPath", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], UpdateQuerySystemUserInput.prototype, "UserQuestion", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], UpdateQuerySystemUserInput.prototype, "Description", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], UpdateQuerySystemUserInput.prototype, "SQL", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], UpdateQuerySystemUserInput.prototype, "TechnicalDescription", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], UpdateQuerySystemUserInput.prototype, "OriginalSQL", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], UpdateQuerySystemUserInput.prototype, "Feedback", void 0);
__decorate([
    Field(() => QueryStatus, { nullable: true }),
    __metadata("design:type", String)
], UpdateQuerySystemUserInput.prototype, "Status", void 0);
__decorate([
    Field(() => Number, { nullable: true }),
    __metadata("design:type", Number)
], UpdateQuerySystemUserInput.prototype, "QualityRank", void 0);
__decorate([
    Field(() => Number, { nullable: true }),
    __metadata("design:type", Number)
], UpdateQuerySystemUserInput.prototype, "ExecutionCostRank", void 0);
__decorate([
    Field(() => Boolean, { nullable: true }),
    __metadata("design:type", Boolean)
], UpdateQuerySystemUserInput.prototype, "UsesTemplate", void 0);
__decorate([
    Field(() => Boolean, { nullable: true }),
    __metadata("design:type", Boolean)
], UpdateQuerySystemUserInput.prototype, "AuditQueryRuns", void 0);
__decorate([
    Field(() => Boolean, { nullable: true }),
    __metadata("design:type", Boolean)
], UpdateQuerySystemUserInput.prototype, "CacheEnabled", void 0);
__decorate([
    Field(() => Number, { nullable: true }),
    __metadata("design:type", Number)
], UpdateQuerySystemUserInput.prototype, "CacheTTLMinutes", void 0);
__decorate([
    Field(() => Number, { nullable: true }),
    __metadata("design:type", Number)
], UpdateQuerySystemUserInput.prototype, "CacheMaxSize", void 0);
__decorate([
    Field(() => [QueryPermissionInputType], { nullable: true }),
    __metadata("design:type", Array)
], UpdateQuerySystemUserInput.prototype, "Permissions", void 0);
UpdateQuerySystemUserInput = __decorate([
    InputType()
], UpdateQuerySystemUserInput);
export { UpdateQuerySystemUserInput };
/**
 * Consolidated result type for Create and Update query mutations.
 * Composes the CodeGen-generated MJQuery_ type so that new entity fields
 * are automatically available in the GraphQL schema without manual sync.
 *
 * On success, Query contains the full query data (scalars + related entities).
 * On failure, Query is null and ErrorMessage describes the problem.
 */
let QueryMutationResultType = class QueryMutationResultType {
};
__decorate([
    Field(() => Boolean),
    __metadata("design:type", Boolean)
], QueryMutationResultType.prototype, "Success", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], QueryMutationResultType.prototype, "ErrorMessage", void 0);
__decorate([
    Field(() => MJQuery_, { nullable: true }),
    __metadata("design:type", MJQuery_)
], QueryMutationResultType.prototype, "Query", void 0);
QueryMutationResultType = __decorate([
    ObjectType()
], QueryMutationResultType);
export { QueryMutationResultType };
let DeleteQueryResultType = class DeleteQueryResultType {
};
__decorate([
    Field(() => Boolean),
    __metadata("design:type", Boolean)
], DeleteQueryResultType.prototype, "Success", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], DeleteQueryResultType.prototype, "ErrorMessage", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], DeleteQueryResultType.prototype, "ID", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], DeleteQueryResultType.prototype, "Name", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], DeleteQueryResultType.prototype, "Description", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], DeleteQueryResultType.prototype, "CategoryID", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], DeleteQueryResultType.prototype, "SQL", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], DeleteQueryResultType.prototype, "Status", void 0);
DeleteQueryResultType = __decorate([
    ObjectType()
], DeleteQueryResultType);
export { DeleteQueryResultType };
let MJQueryResolverExtended = class MJQueryResolverExtended extends MJQueryResolver {
    /**
     * Creates a new query with the provided attributes. This mutation is restricted to system users only.
     * @param input - CreateQuerySystemUserInput containing all the query attributes
     * @param context - Application context containing user information
     * @returns CreateQueryResultType with success status and query data
     */
    async CreateQuerySystemUser(input, context, pubSub) {
        try {
            // Handle CategoryPath if provided
            let finalCategoryID = input.CategoryID;
            const provider = GetReadWriteProvider(context.providers);
            if (input.CategoryPath) {
                finalCategoryID = await this.findOrCreateCategoryPath(input.CategoryPath, provider, context.userPayload.userRecord);
            }
            // Check for existing query with same name in the same category
            const existingQuery = await this.findExistingQuery(provider, input.Name, finalCategoryID, context.userPayload.userRecord);
            if (existingQuery) {
                const categoryInfo = input.CategoryPath ? `category path '${input.CategoryPath}'` : `category ID '${finalCategoryID}'`;
                return {
                    Success: false,
                    ErrorMessage: `Query with name '${input.Name}' already exists in ${categoryInfo}`
                };
            }
            // Use MJQueryEntityServer which handles AI processing
            const record = await provider.GetEntityObject("MJ: Queries", context.userPayload.userRecord);
            // Destructure out non-database fields, keep only fields to persist
            const { Permissions: _permissions, CategoryPath: _categoryPath, ...fieldsToSet } = {
                ...input,
                CategoryID: finalCategoryID || input.CategoryID,
                Status: input.Status || 'Approved',
                QualityRank: input.QualityRank || 0,
                UsesTemplate: input.UsesTemplate || false,
                AuditQueryRuns: input.AuditQueryRuns || false,
                CacheEnabled: input.CacheEnabled || false,
                CacheTTLMinutes: input.CacheTTLMinutes || null,
                CacheMaxSize: input.CacheMaxSize || null
            };
            record.SetMany(fieldsToSet, true);
            this.ListenForEntityMessages(record, pubSub, context.userPayload.userRecord);
            // Attempt to save the query
            const saveResult = await record.Save();
            if (saveResult) {
                // Save succeeded - fire the AfterCreate event and return all the data
                await this.AfterCreate(provider, input); // fire event
                const queryID = record.ID;
                if (input.Permissions && input.Permissions.length > 0) {
                    await this.createPermissions(provider, input.Permissions, queryID, context.userPayload.userRecord);
                    await record.RefreshRelatedMetadata(true); // force DB update since we just created new permissions
                }
                // Refresh metadata cache to include the newly created query
                // This ensures subsequent operations can find the query without additional DB calls
                await provider.Refresh();
                return this.buildSuccessResult(record);
            }
            else {
                // Save failed - check if another request created the same query (race condition)
                // Always recheck regardless of error type to handle all duplicate scenarios
                const existingQuery = await this.findExistingQuery(provider, input.Name, finalCategoryID, context.userPayload.userRecord);
                if (existingQuery) {
                    // Found the query that was created by another request — load it as a full entity
                    // so that related metadata (Fields, Parameters, Entities, Permissions) is populated
                    LogStatus(`[CreateQuery] Unique constraint detected for query '${input.Name}'. Using existing query (ID: ${existingQuery.ID}) created by concurrent request.`);
                    const existingEntity = await provider.GetEntityObject('MJ: Queries', context.userPayload.userRecord);
                    if (await existingEntity.Load(existingQuery.ID)) {
                        return this.buildSuccessResult(existingEntity);
                    }
                    // Entity load failed after confirming the row exists — extremely rare
                    return {
                        Success: false,
                        ErrorMessage: `Found query '${input.Name}' created by concurrent request (ID: ${existingQuery.ID}) but failed to load it as entity`
                    };
                }
                // Genuine failure - couldn't find an existing query with the same name
                const errorMessage = record.LatestResult?.Message || '';
                return {
                    Success: false,
                    ErrorMessage: `Failed to create query: ${errorMessage || 'Unknown error'}`
                };
            }
        }
        catch (err) {
            LogError(err);
            return {
                Success: false,
                ErrorMessage: `MJQueryResolverExtended::CreateQuerySystemUser --- Error creating query: ${err instanceof Error ? err.message : String(err)}`
            };
        }
    }
    /**
     * Maps an MJQueryEntityServer (with loaded related metadata) to a QueryMutationResultType.
     * Uses entity.GetAll() for scalar fields so that new CodeGen-generated fields are included
     * automatically without manual updates. Related entity arrays are mapped explicitly.
     */
    buildSuccessResult(entity) {
        return {
            Success: true,
            Query: {
                ...entity.GetAll(),
                MJQueryFields_QueryIDArray: this.mapFields(entity.QueryFields),
                MJQueryParameters_QueryIDArray: this.mapParameters(entity.QueryParameters),
                MJQueryEntities_QueryIDArray: this.mapEntities(entity.QueryEntities),
                MJQueryPermissions_QueryIDArray: this.mapPermissions(entity.QueryPermissions),
            }
        };
    }
    mapFields(fields) {
        return fields.map(f => ({
            ID: f.ID,
            QueryID: f.QueryID,
            Name: f.Name,
            Description: f.Description,
            Sequence: f.Sequence,
            SQLBaseType: f.SQLBaseType,
            SQLFullType: f.SQLFullType,
            SourceEntityID: f.SourceEntityID,
            SourceEntity: f.SourceEntity,
            SourceFieldName: f.SourceFieldName,
            IsComputed: f.IsComputed,
            ComputationDescription: f.ComputationDescription,
            IsSummary: f.IsSummary,
            SummaryDescription: f.SummaryDescription,
            _mj__CreatedAt: f.__mj_CreatedAt,
            _mj__UpdatedAt: f.__mj_UpdatedAt,
            DetectionMethod: f.DetectionMethod,
            AutoDetectConfidenceScore: f.AutoDetectConfidenceScore,
            Query: '',
        }));
    }
    mapParameters(params) {
        return params.map(p => ({
            ID: p.ID,
            QueryID: p.QueryID,
            Name: p.Name,
            Description: p.Description,
            Type: p.Type,
            IsRequired: p.IsRequired,
            DefaultValue: p.DefaultValue,
            SampleValue: p.SampleValue,
            ValidationFilters: p.ValidationFilters,
            _mj__CreatedAt: p.__mj_CreatedAt,
            _mj__UpdatedAt: p.__mj_UpdatedAt,
            DetectionMethod: p.DetectionMethod,
            AutoDetectConfidenceScore: p.AutoDetectConfidenceScore,
            Query: p.Query ?? '',
        }));
    }
    mapEntities(entities) {
        return entities.map(e => ({
            ID: e.ID,
            QueryID: e.QueryID,
            EntityID: e.EntityID,
            Entity: e.Entity,
            _mj__CreatedAt: e.__mj_CreatedAt,
            _mj__UpdatedAt: e.__mj_UpdatedAt,
            DetectionMethod: e.DetectionMethod,
            AutoDetectConfidenceScore: e.AutoDetectConfidenceScore,
            Query: e.Query ?? '',
        }));
    }
    mapPermissions(permissions) {
        return permissions.map(p => ({
            ID: p.ID,
            QueryID: p.QueryID,
            RoleID: p.RoleID,
            Role: p.Role,
            _mj__CreatedAt: new Date(),
            _mj__UpdatedAt: new Date(),
            Query: p.Query ?? '',
        }));
    }
    async createPermissions(p, permissions, queryID, contextUser) {
        for (const perm of permissions) {
            const permissionEntity = await p.GetEntityObject('MJ: Query Permissions', contextUser);
            if (permissionEntity) {
                permissionEntity.QueryID = queryID;
                permissionEntity.RoleID = perm.RoleID;
                await permissionEntity.Save();
            }
        }
    }
    /**
     * Updates an existing query with the provided attributes. This mutation is restricted to system users only.
     * @param input - UpdateQuerySystemUserInput containing the query ID and fields to update
     * @param context - Application context containing user information
     * @returns UpdateQueryResultType with success status and updated query data including related entities
     */
    async UpdateQuerySystemUser(input, context, pubSub) {
        try {
            // Load the existing query using MJQueryEntityServer
            const provider = GetReadWriteProvider(context.providers);
            const queryEntity = await provider.GetEntityObject('MJ: Queries', context.userPayload.userRecord);
            if (!queryEntity || !await queryEntity.Load(input.ID)) {
                return {
                    Success: false,
                    ErrorMessage: `Query with ID ${input.ID} not found`
                };
            }
            // Handle CategoryPath if provided
            let finalCategoryID = input.CategoryID;
            if (input.CategoryPath) {
                finalCategoryID = await this.findOrCreateCategoryPath(input.CategoryPath, provider, context.userPayload.userRecord);
            }
            // now make sure there is NO existing query by the same name in the specified category
            const existingQueryResult = await provider.RunView({
                EntityName: 'MJ: Queries',
                ExtraFilter: `Name='${input.Name}' AND CategoryID='${finalCategoryID}'`
            }, context.userPayload.userRecord);
            if (existingQueryResult.Success && existingQueryResult.Results?.length > 0) {
                // we have a match! Let's return an error
                return {
                    Success: false,
                    ErrorMessage: `Query with name '${input.Name}' already exists in the specified ${input.CategoryID ? 'category' : 'categoryPath'}`
                };
            }
            // Update fields that were provided
            const updateFields = {};
            if (input.Name !== undefined)
                updateFields.Name = input.Name;
            if (finalCategoryID !== undefined)
                updateFields.CategoryID = finalCategoryID;
            if (input.UserQuestion !== undefined)
                updateFields.UserQuestion = input.UserQuestion;
            if (input.Description !== undefined)
                updateFields.Description = input.Description;
            if (input.SQL !== undefined)
                updateFields.SQL = input.SQL;
            if (input.TechnicalDescription !== undefined)
                updateFields.TechnicalDescription = input.TechnicalDescription;
            if (input.OriginalSQL !== undefined)
                updateFields.OriginalSQL = input.OriginalSQL;
            if (input.Feedback !== undefined)
                updateFields.Feedback = input.Feedback;
            if (input.Status !== undefined)
                updateFields.Status = input.Status;
            if (input.QualityRank !== undefined)
                updateFields.QualityRank = input.QualityRank;
            if (input.ExecutionCostRank !== undefined)
                updateFields.ExecutionCostRank = input.ExecutionCostRank;
            if (input.UsesTemplate !== undefined)
                updateFields.UsesTemplate = input.UsesTemplate;
            if (input.AuditQueryRuns !== undefined)
                updateFields.AuditQueryRuns = input.AuditQueryRuns;
            if (input.CacheEnabled !== undefined)
                updateFields.CacheEnabled = input.CacheEnabled;
            if (input.CacheTTLMinutes !== undefined)
                updateFields.CacheTTLMinutes = input.CacheTTLMinutes;
            if (input.CacheMaxSize !== undefined)
                updateFields.CacheMaxSize = input.CacheMaxSize;
            // Use SetMany to update all fields at once
            queryEntity.SetMany(updateFields);
            // Save the updated query
            const saveResult = await queryEntity.Save();
            if (!saveResult) {
                return {
                    Success: false,
                    ErrorMessage: `Failed to update query: ${queryEntity.LatestResult?.Message || 'Unknown error'}`
                };
            }
            const queryID = queryEntity.ID;
            // Handle permissions update if provided
            if (input.Permissions !== undefined) {
                // Delete existing permissions
                const rv = new RunView();
                const existingPermissions = await rv.RunView({
                    EntityName: 'MJ: Query Permissions',
                    ExtraFilter: `QueryID='${queryID}'`,
                    ResultType: 'entity_object'
                }, context.userPayload.userRecord);
                if (existingPermissions.Success && existingPermissions.Results) {
                    for (const perm of existingPermissions.Results) {
                        await perm.Delete();
                    }
                }
                // Create new permissions
                await this.createPermissions(provider, input.Permissions, queryID, context.userPayload.userRecord);
                // Refresh the metadata to get updated permissions
                await queryEntity.RefreshRelatedMetadata(true);
            }
            return this.buildSuccessResult(queryEntity);
        }
        catch (err) {
            LogError(err);
            return {
                Success: false,
                ErrorMessage: `MJQueryResolverExtended::UpdateQuerySystemUser --- Error updating query: ${err instanceof Error ? err.message : String(err)}`
            };
        }
    }
    /**
     * Deletes a query by ID. This mutation is restricted to system users only.
     * @param ID - The ID of the query to delete
     * @param options - Delete options controlling action execution
     * @param context - Application context containing user information
     * @returns DeleteQueryResultType with success status and deleted query data
     */
    async DeleteQuerySystemResolver(ID, options, context, pubSub) {
        try {
            // Validate ID is not null/undefined/empty
            if (!ID || ID.trim() === '') {
                return {
                    Success: false,
                    ErrorMessage: 'MJQueryResolverExtended::DeleteQuerySystemResolver --- Invalid query ID: ID cannot be null or empty'
                };
            }
            const provider = GetReadWriteProvider(context.providers);
            const key = new CompositeKey([{ FieldName: 'ID', Value: ID }]);
            // Provide default options if none provided
            const deleteOptions = options || {
                SkipEntityAIActions: false,
                SkipEntityActions: false,
                ReplayOnly: false,
                IsParentEntityDelete: false
            };
            // Use inherited DeleteRecord method from ResolverBase
            const deletedQuery = await this.DeleteRecord('MJ: Queries', key, deleteOptions, provider, context.userPayload, pubSub);
            if (deletedQuery) {
                return {
                    Success: true,
                    ID: deletedQuery.ID,
                    Name: deletedQuery.Name,
                    Description: deletedQuery.Description,
                    CategoryID: deletedQuery.CategoryID,
                    SQL: deletedQuery.SQL,
                    Status: deletedQuery.Status
                };
            }
            else {
                return {
                    Success: false,
                    ErrorMessage: 'Failed to delete query using DeleteRecord method'
                };
            }
        }
        catch (err) {
            LogError(err);
            return {
                Success: false,
                ErrorMessage: `MJQueryResolverExtended::DeleteQuerySystemResolver --- Error deleting query: ${err instanceof Error ? err.message : String(err)}`
            };
        }
    }
    /**
     * Finds or creates a category hierarchy based on the provided path.
     * Path format: "Parent/Child/Grandchild" - case insensitive lookup and creation.
     * @param categoryPath - Slash-separated category path
     * @param md - Metadata instance
     * @param contextUser - User context for operations
     * @returns The ID of the final category in the path
     */
    async findOrCreateCategoryPath(categoryPath, p, contextUser) {
        if (!categoryPath || categoryPath.trim() === '') {
            throw new Error('CategoryPath cannot be empty');
        }
        const pathParts = categoryPath.split('/').map(part => part.trim()).filter(part => part.length > 0);
        if (pathParts.length === 0) {
            throw new Error('CategoryPath must contain at least one valid category name');
        }
        let currentParentID = null;
        let currentCategoryID = null;
        for (let i = 0; i < pathParts.length; i++) {
            const categoryName = pathParts[i];
            // Look for existing category at this level
            const existingCategory = await this.findCategoryByNameAndParent(p, categoryName, currentParentID, contextUser);
            if (existingCategory) {
                currentCategoryID = existingCategory.ID;
                currentParentID = existingCategory.ID;
            }
            else {
                try {
                    // Create new category
                    const newCategory = await p.GetEntityObject("MJ: Query Categories", contextUser);
                    if (!newCategory) {
                        throw new Error(`Failed to create entity object for Query Categories`);
                    }
                    newCategory.Name = categoryName;
                    newCategory.ParentID = currentParentID;
                    newCategory.UserID = contextUser.ID;
                    newCategory.Description = `Auto-created category from path: ${categoryPath}`;
                    const saveResult = await newCategory.Save();
                    if (!saveResult) {
                        // Save failed - always recheck if another request created the same category
                        const recheckExisting = await this.findCategoryByNameAndParent(p, categoryName, currentParentID, contextUser);
                        if (recheckExisting) {
                            // Another request created it - use that one
                            LogStatus(`[CreateQuery] Unique constraint detected for category '${categoryName}'. Using existing category (ID: ${recheckExisting.ID}) created by concurrent request.`);
                            currentCategoryID = recheckExisting.ID;
                            currentParentID = recheckExisting.ID;
                        }
                        else {
                            // Genuine failure (not a duplicate)
                            const errorMessage = newCategory.LatestResult?.Message || '';
                            throw new Error(`Failed to create category '${categoryName}': ${errorMessage || 'Unknown error'}`);
                        }
                    }
                    else {
                        currentCategoryID = newCategory.ID;
                        currentParentID = newCategory.ID;
                    }
                }
                catch (error) {
                    // On error, double-check if category exists (race condition handling)
                    const recheckExisting = await this.findCategoryByNameAndParent(p, categoryName, currentParentID, contextUser);
                    if (recheckExisting) {
                        // Category exists, another request created it
                        LogStatus(`[CreateQuery] Exception during category creation for '${categoryName}'. Using existing category (ID: ${recheckExisting.ID}) created by concurrent request.`);
                        currentCategoryID = recheckExisting.ID;
                        currentParentID = recheckExisting.ID;
                    }
                    else {
                        throw new Error(`Failed to create category '${categoryName}': ${error instanceof Error ? error.message : String(error)}`);
                    }
                }
            }
        }
        if (!currentCategoryID) {
            throw new Error('Failed to determine final category ID');
        }
        return currentCategoryID;
    }
    /**
     * Finds an existing query by name and category ID using RunView.
     * Bypasses metadata cache to ensure we get the latest data from database.
     * @param provider - Database provider
     * @param queryName - Name of the query to find
     * @param categoryID - Category ID (can be null)
     * @param contextUser - User context for database operations
     * @returns The matching query row or null if not found
     */
    async findExistingQuery(provider, queryName, categoryID, contextUser) {
        try {
            // Query database directly to avoid cache staleness issues
            const categoryFilter = categoryID ? `CategoryID='${categoryID}'` : 'CategoryID IS NULL';
            const nameFilter = `LOWER(Name) = LOWER('${queryName.replace(/'/g, "''")}')`;
            const result = await provider.RunView({
                EntityName: 'MJ: Queries',
                ExtraFilter: `${nameFilter} AND ${categoryFilter}`
            }, contextUser);
            if (result.Success && result.Results && result.Results.length > 0) {
                return result.Results[0];
            }
            return null;
        }
        catch (error) {
            // If query fails, return null (query doesn't exist)
            return null;
        }
    }
    /**
     * Finds a category by name and parent ID using RunView.
     * Bypasses metadata cache to ensure we get the latest data from database.
     * @param categoryName - Name of the category to find
     * @param parentID - Parent category ID (null for root level)
     * @param contextUser - User context for database operations
     * @returns The matching category entity or null if not found
     */
    async findCategoryByNameAndParent(provider, categoryName, parentID, contextUser) {
        try {
            // Query database directly to avoid cache staleness issues
            const parentFilter = parentID ? `ParentID='${parentID}'` : 'ParentID IS NULL';
            const nameFilter = `LOWER(Name) = LOWER('${categoryName.replace(/'/g, "''")}')`; // Escape single quotes
            const result = await provider.RunView({
                EntityName: 'MJ: Query Categories',
                ExtraFilter: `${nameFilter} AND ${parentFilter}`,
                ResultType: 'entity_object'
            }, contextUser);
            if (result.Success && result.Results && result.Results.length > 0) {
                return result.Results[0];
            }
            return null;
        }
        catch (error) {
            // If query fails, return null
            return null;
        }
    }
};
__decorate([
    RequireSystemUser(),
    Mutation(() => QueryMutationResultType),
    __param(0, Arg('input', () => CreateQuerySystemUserInput)),
    __param(1, Ctx()),
    __param(2, PubSub()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [CreateQuerySystemUserInput, Object, PubSubEngine]),
    __metadata("design:returntype", Promise)
], MJQueryResolverExtended.prototype, "CreateQuerySystemUser", null);
__decorate([
    RequireSystemUser(),
    Mutation(() => QueryMutationResultType),
    __param(0, Arg('input', () => UpdateQuerySystemUserInput)),
    __param(1, Ctx()),
    __param(2, PubSub()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [UpdateQuerySystemUserInput, Object, PubSubEngine]),
    __metadata("design:returntype", Promise)
], MJQueryResolverExtended.prototype, "UpdateQuerySystemUser", null);
__decorate([
    RequireSystemUser(),
    Mutation(() => DeleteQueryResultType),
    __param(0, Arg('ID', () => String)),
    __param(1, Arg('options', () => DeleteOptionsInput, { nullable: true })),
    __param(2, Ctx()),
    __param(3, PubSub()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, DeleteOptionsInput, Object, PubSubEngine]),
    __metadata("design:returntype", Promise)
], MJQueryResolverExtended.prototype, "DeleteQuerySystemResolver", null);
MJQueryResolverExtended = __decorate([
    Resolver()
], MJQueryResolverExtended);
export { MJQueryResolverExtended };
//# sourceMappingURL=QuerySystemUserResolver.js.map