import { sql, eq, and } from 'drizzle-orm';
import { getDatabase } from './db.js';
/**
 * Relation builder for dynamic schemas
 */
export class RelationBuilder {
    relationsMap = new Map();
    /** Reverse index: target collection → M2A junction info for O(1) delete lookups */
    m2aTargetIndex = null;
    /**
     * Store association definitions for a table
     * Relations will be resolved at query time using Drizzle's query API
     * Note: This merges with existing associations instead of replacing them
     */
    storeAssociations(tableName, associations) {
        console.log(`[RelationBuilder] Storing associations for ${tableName}:`, Object.keys(associations));
        // Get existing associations for this table
        const existing = this.relationsMap.get(tableName) || {};
        // Merge new associations with existing ones
        const merged = { ...existing, ...associations };
        console.log(`[RelationBuilder] After merge, ${tableName} has:`, Object.keys(merged));
        this.relationsMap.set(tableName, merged);
        // Invalidate reverse index so it rebuilds on next lookup
        this.m2aTargetIndex = null;
    }
    /**
     * Get associations for a table
     */
    getAssociations(tableName) {
        const assocs = this.relationsMap.get(tableName);
        console.log(`[RelationBuilder] Retrieved associations for ${tableName}:`, assocs ? Object.keys(assocs) : 'none');
        return assocs;
    }
    /**
     * Get all associations
     */
    getAllAssociations() {
        return this.relationsMap;
    }
    /**
     * Get foreign key column name for a relation
     */
    getForeignKey(assoc, defaultKey) {
        return assoc.foreignKey || defaultKey || `${assoc.model.toLowerCase()}Id`;
    }
    /**
     * Check if an association is a one-to-many type
     */
    isOneToMany(assoc) {
        return assoc.type === 'HasMany';
    }
    /**
     * Check if an association is a many-to-one type
     */
    isManyToOne(assoc) {
        return assoc.type === 'BelongsTo';
    }
    /**
     * Check if an association is a many-to-many type
     */
    isManyToMany(assoc) {
        return assoc.type === 'BelongsToMany';
    }
    /**
     * Get M2A junction models that reference a given target collection.
     * Uses a lazily-built reverse index for O(1) lookups instead of scanning all associations.
     */
    getM2AJunctionsForTarget(collection) {
        if (!this.m2aTargetIndex) {
            // Build the reverse index once
            this.m2aTargetIndex = new Map();
            for (const [, associations] of this.relationsMap) {
                for (const [, assoc] of Object.entries(associations)) {
                    const { type, model, polymorphic, tables } = assoc;
                    if (type !== 'HasMany' || !polymorphic || !tables)
                        continue;
                    for (const target of tables) {
                        let entries = this.m2aTargetIndex.get(target);
                        if (!entries) {
                            entries = [];
                            this.m2aTargetIndex.set(target, entries);
                        }
                        // Avoid duplicates
                        if (!entries.some(e => e.model === model)) {
                            entries.push({ model });
                        }
                    }
                }
            }
        }
        return this.m2aTargetIndex.get(collection) || [];
    }
}
/**
 * Singleton instance
 */
export const relationBuilder = new RelationBuilder();
/**
 * Helper to create foreign key constraint SQL
 */
export function createForeignKeySQL(tableName, columnName, referencedTable, referencedColumn = 'id', onDelete = 'CASCADE', onUpdate = 'CASCADE') {
    const constraintName = `fk_${tableName}_${columnName}`;
    return `
    ALTER TABLE "${tableName}"
    ADD CONSTRAINT "${constraintName}"
    FOREIGN KEY ("${columnName}")
    REFERENCES "${referencedTable}"("${referencedColumn}")
    ON DELETE ${onDelete}
    ON UPDATE ${onUpdate}
  `.trim();
}
/**
 * Helper to check if a field is a polymorphic relation
 */
export function isPolymorphicRelation(assoc) {
    return assoc.type === 'M2A' || assoc.polymorphic === true;
}
/**
 * Helper to get polymorphic field names
 */
export function getPolymorphicFields(relationName) {
    return {
        typeField: `${relationName}Type`,
        idField: `${relationName}Id`,
    };
}
/**
 * Build junction table for many-to-many relations
 * Example: UserRoles for User <-> Role
 */
export function buildJunctionTable(table1Name, table2Name, table1Key = 'id', table2Key = 'id') {
    const junctionName = `${table1Name}${table2Name}`;
    const fk1 = `${table1Name}${table1Key.charAt(0).toUpperCase()}${table1Key.slice(1)}`;
    const fk2 = `${table2Name}${table2Key.charAt(0).toUpperCase()}${table2Key.slice(1)}`;
    return `
    CREATE TABLE IF NOT EXISTS "${junctionName}" (
      "${fk1}" UUID NOT NULL,
      "${fk2}" UUID NOT NULL,
      "createdAt" TIMESTAMPTZ NOT NULL DEFAULT NOW(),
      "updatedAt" TIMESTAMPTZ NOT NULL DEFAULT NOW(),
      PRIMARY KEY ("${fk1}", "${fk2}"),
      FOREIGN KEY ("${fk1}") REFERENCES "${table1Name}"("${table1Key}") ON DELETE CASCADE,
      FOREIGN KEY ("${fk2}") REFERENCES "${table2Name}"("${table2Key}") ON DELETE CASCADE
    )
  `.trim();
}
/**
 * Convert Sequelize association type to Drizzle relation type
 */
export function sequelizeTosDrizzleRelationType(sequelizeType) {
    switch (sequelizeType) {
        case 'HasMany':
        case 'BelongsToMany':
            return 'many';
        case 'HasOne':
        case 'BelongsTo':
            return 'one';
        default:
            return null;
    }
}
// ============================================================================
// Relational Data Processing
// ============================================================================
/**
 * Process relational data - extract nested objects/arrays
 * @param collection - Collection name
 * @param data - Data to process
 * @param service - Service instance
 * @param ItemsServiceClass - ItemsService class for creating related service instances
 */
export async function processRelationalData(collection, data, service, ItemsServiceClass) {
    console.log(`[RelationUtils] Processing relational data for ${collection}`);
    const result = {};
    const deferredHasMany = [];
    const deferredM2M = [];
    const deferredM2A = [];
    // Get relation metadata for this collection
    const associations = relationBuilder.getAssociations(collection);
    console.log(`[RelationUtils] Associations for ${collection}:`, associations ? Object.keys(associations) : 'none');
    if (!associations) {
        // No relations defined, return data as-is
        console.log(`[RelationUtils] No associations found for ${collection}, returning data as-is`);
        return {
            result: { ...data },
            deferredHasMany,
            deferredM2M,
            deferredM2A
        };
    }
    // Process BelongsTo relationships first - they need to be created/resolved before main record
    for (const [key, value] of Object.entries(data)) {
        const association = associations[key];
        if (!association || value == null) {
            // Not a relation or value is null - include in result
            result[key] = value;
            continue;
        }
        if (association.type === 'BelongsTo') {
            console.log(`[RelationUtils] Processing BelongsTo relation: ${key}`);
            // Use passed ItemsService class to create related service
            const relatedService = new ItemsServiceClass(association.model, {
                accountability: service.accountability,
                tenant: service.tenant
            });
            const foreignKey = association.foreignKey || `${key}_Id`;
            if (typeof value === 'object' && !value.id) {
                // Create new related record - inherit tenant_Id from parent data if available
                const belongsToData = data.tenant_Id && !value.tenant_Id
                    ? { ...value, tenant_Id: data.tenant_Id }
                    : value;
                console.log(`[RelationUtils] Creating new ${association.model} for ${key}`);
                const newRelatedId = await relatedService.createOne(belongsToData, { bypassPermissions: true });
                console.log(`[RelationUtils] Created ${association.model} with ID:`, newRelatedId);
                console.log(`[RelationUtils] Setting ${foreignKey} =`, newRelatedId);
                result[foreignKey] = newRelatedId;
            }
            else if (typeof value === 'object' && value.id) {
                // Reference existing record (optionally update it)
                console.log(`[RelationUtils] Using existing ${association.model} ${value.id} for ${key}`);
                // If there are other fields besides id, update the related record
                const updateFields = { ...value };
                delete updateFields.id;
                if (Object.keys(updateFields).length > 0) {
                    await relatedService.updateOne(value.id, updateFields, { bypassPermissions: true });
                }
                result[foreignKey] = value.id;
            }
            else {
                // Use existing record ID directly
                result[foreignKey] = value;
            }
            // Don't include the relation name in result (we stored the foreignKey instead)
            // delete result[key]; - already not added
        }
        else {
            // Not a BelongsTo - include in result for now, process later
            result[key] = value;
        }
    }
    // Process HasMany, BelongsToMany, and M2A relationships - these are deferred
    for (const [key, value] of Object.entries(data)) {
        const association = associations[key];
        if (!association || value == null)
            continue;
        // Check for M2A (polymorphic) relations first
        // M2A is stored as HasMany with polymorphic: true
        if (isPolymorphicRelation(association)) {
            if (Array.isArray(value)) {
                console.log(`[RelationUtils] Deferring M2A relation: ${key}`);
                deferredM2A.push({ association: key, associationInfo: association, value });
            }
            // Remove from result
            delete result[key];
        }
        else if (association.type === 'HasMany') {
            if (Array.isArray(value)) {
                console.log(`[RelationUtils] Deferring HasMany relation: ${key}`);
                deferredHasMany.push({ association: key, associationInfo: association, value });
            }
            // Remove from result
            delete result[key];
        }
        else if (association.type === 'BelongsToMany') {
            if (Array.isArray(value)) {
                console.log(`[RelationUtils] Deferring BelongsToMany relation: ${key}`);
                deferredM2M.push({ association: key, associationInfo: association, value });
            }
            // Remove from result
            delete result[key];
        }
    }
    console.log(`[RelationUtils] Processed relational data:`, {
        resultKeys: Object.keys(result),
        deferredHasManyCount: deferredHasMany.length,
        deferredM2MCount: deferredM2M.length,
        deferredM2ACount: deferredM2A.length
    });
    return {
        result,
        deferredHasMany,
        deferredM2M,
        deferredM2A
    };
}
/**
 * Handle HasMany relationship after main record is created
 *
 * @param item - The created/updated main record with its ID
 * @param association - Name of the association
 * @param associationInfo - Metadata about the association
 * @param value - Array of related items to create/update
 * @param service - The service instance
 * @param ItemsServiceClass - ItemsService class for creating related service instances
 * @param transaction - Optional transaction
 */
export async function handleHasManyRelationship(item, association, associationInfo, value, service, ItemsServiceClass, transaction) {
    console.log(`[RelationUtils] Handling HasMany relationship: ${association}`);
    if (!Array.isArray(value)) {
        console.warn(`[RelationUtils] HasMany value is not an array for ${association}`);
        return;
    }
    // Use passed ItemsService class to create related service
    const relatedService = new ItemsServiceClass(associationInfo.model, {
        accountability: service.accountability,
        tenant: service.tenant
    });
    const foreignKey = associationInfo.foreignKey || `${service.collection.toLowerCase()}_Id`;
    const parentId = item[service.primaryKey];
    // Get existing related records
    const existingRecordsResult = await relatedService.readByQuery({
        filter: { [foreignKey]: { eq: parentId } }
    }, true); // bypassPermissions
    const existingRecords = existingRecordsResult.data || [];
    // Create a set of existing IDs
    const existingIds = new Set(existingRecords.map((record) => record.id));
    // Create a set of IDs from the update value
    const updateIds = new Set(value.filter(item => item.id).map(item => item.id));
    // Find records to delete or unlink
    const idsToDelete = [...existingIds].filter(id => !updateIds.has(id));
    if (idsToDelete.length > 0) {
        console.log(`[RelationUtils] Removing ${idsToDelete.length} orphaned HasMany records`);
        // Check if foreign key is nullable by looking at schema
        const { schemaManager } = await import('./schemaManager.js');
        const targetSchema = await schemaManager.getSchemaDefinition(associationInfo.model);
        const fkField = targetSchema?.fields?.[foreignKey];
        const allowsNull = !fkField || fkField.allowNull !== false;
        // For junction tables or non-nullable foreign keys, delete the records
        // For nullable foreign keys, just set the FK to null (unlink)
        // Check both the schema property and name suffix for backward compatibility
        const isJunctionTable = targetSchema?.isJunction === true || associationInfo.model.endsWith('_junction');
        if (isJunctionTable || !allowsNull) {
            await Promise.all(idsToDelete.map(async (id) => {
                await relatedService.deleteOne(id, { bypassPermissions: true, transaction });
            }));
        }
        else {
            // Set foreign key to null instead of deleting
            await Promise.all(idsToDelete.map(async (id) => {
                await relatedService.updateOne(id, { [foreignKey]: null }, { bypassPermissions: true, transaction });
            }));
        }
    }
    // Create or update the related records
    await Promise.all(value.map(async (relItem) => {
        const data = { ...relItem };
        // Set the foreign key to link to parent
        data[foreignKey] = parentId;
        // Inherit tenant_Id from parent item if available and not already set
        if (item.tenant_Id && !data.tenant_Id) {
            data.tenant_Id = item.tenant_Id;
        }
        if (relItem.id) {
            // Update existing record
            console.log(`[RelationUtils] Updating HasMany record ${relItem.id} for ${association}`);
            await relatedService.updateOne(relItem.id, data, { bypassPermissions: true, transaction });
        }
        else {
            // Create new record
            console.log(`[RelationUtils] Creating new HasMany record for ${association}`);
            await relatedService.createOne(data, { bypassPermissions: true, transaction });
        }
    }));
    console.log(`[RelationUtils] Completed HasMany relationship: ${association}`);
}
/**
 * Handle M2M (BelongsToMany) relationship after main record is created
 *
 * @param item - The created/updated main record with its ID
 * @param association - Name of the association
 * @param associationInfo - Metadata about the association
 * @param value - Array of related items (IDs or objects with IDs)
 * @param service - The service instance
 * @param ItemsServiceClass - ItemsService class for creating related service instances
 * @param transaction - Optional transaction
 */
export async function handleM2MRelationship(item, association, associationInfo, value, service, ItemsServiceClass, transaction) {
    console.log(`[RelationUtils] Handling M2M relationship: ${association}`);
    if (!Array.isArray(value)) {
        console.warn(`[RelationUtils] M2M value is not an array for ${association}`);
        return;
    }
    // Use statically imported getDatabase and sql
    const db = getDatabase();
    // Use transaction if provided, otherwise use db
    const dbOrTx = transaction || db;
    // Get junction table name from association metadata
    const junctionTable = associationInfo.through || `${service.collection}_${associationInfo.model}_junction`;
    console.log(`[RelationUtils] Using junction table: ${junctionTable}`);
    // Define foreign key column names
    const sourceKey = associationInfo.foreignKey || `${service.collection}_id`;
    const targetKey = associationInfo.otherKey || `${associationInfo.model}_id`;
    const parentId = item[service.primaryKey];
    console.log(`[RelationUtils] M2M keys: sourceKey=${sourceKey}, targetKey=${targetKey}, parentId=${parentId}`);
    // Process value array - create any new related records first
    const processedIds = [];
    for (const targetItem of value) {
        if (typeof targetItem === 'object' && targetItem !== null) {
            if (targetItem.id) {
                // Existing record - just use the ID
                processedIds.push(targetItem.id);
            }
            else {
                // New record - create it first using passed ItemsService class
                const relatedService = new ItemsServiceClass(associationInfo.model, {
                    accountability: service.accountability,
                    tenant: service.tenant
                });
                // Inherit tenant_Id from parent item if available
                const createData = (item.tenant_Id && !targetItem.tenant_Id)
                    ? { ...targetItem, tenant_Id: item.tenant_Id }
                    : targetItem;
                console.log(`[RelationUtils] Creating new ${associationInfo.model} for M2M relation`);
                const newId = await relatedService.createOne(createData, { bypassPermissions: true, transaction });
                processedIds.push(newId);
            }
        }
        else {
            // Direct ID
            processedIds.push(targetItem);
        }
    }
    // Clear existing relations for this record
    console.log(`[RelationUtils] Clearing existing M2M relations in ${junctionTable}`);
    await dbOrTx.execute(sql `
    DELETE FROM "${sql.raw(junctionTable)}"
    WHERE "${sql.raw(sourceKey)}" = ${parentId}
  `);
    // Create new junction records
    if (processedIds.length > 0) {
        console.log(`[RelationUtils] Creating ${processedIds.length} M2M junction records`);
        for (const targetId of processedIds) {
            await dbOrTx.execute(sql `
        INSERT INTO "${sql.raw(junctionTable)}" ("${sql.raw(sourceKey)}", "${sql.raw(targetKey)}")
        VALUES (${parentId}, ${targetId})
      `);
        }
    }
    console.log(`[RelationUtils] Completed M2M relationship: ${association}`);
}
/**
 * Handle M2A (polymorphic) relationship after main record is created
 *
 * @param item - The created/updated main record with its ID
 * @param association - Name of the association
 * @param associationInfo - Metadata about the association
 * @param value - Array of polymorphic relation items
 * @param service - The service instance
 * @param ItemsServiceClass - ItemsService class (not used in M2A but kept for consistency)
 * @param transaction - Optional transaction
 */
export async function handleM2ARelationship(item, association, associationInfo, value, service, ItemsServiceClass, transaction) {
    console.log(`[RelationUtils] Handling M2A relationship: ${association}`);
    if (!Array.isArray(value)) {
        console.warn(`[RelationUtils] M2A value is not an array for ${association}`);
        return;
    }
    // Use statically imported getDatabase and sql
    const db = getDatabase();
    // Use transaction if provided, otherwise use db
    const dbOrTx = transaction || db;
    // M2A uses a polymorphic junction table
    // The junction table name is stored in 'through' property
    const junctionTable = associationInfo.through;
    if (!junctionTable) {
        console.error(`[RelationUtils] M2A relation ${association} missing 'through' property`);
        return;
    }
    console.log(`[RelationUtils] Using M2A junction table: ${junctionTable}`);
    // Define column names for polymorphic relation
    const sourceKey = `${service.collection}_id`;
    const targetKey = 'item_id'; // Polymorphic ID field
    const typeKey = 'collection'; // Polymorphic type field
    const parentId = item[service.primaryKey];
    console.log(`[RelationUtils] M2A keys: sourceKey=${sourceKey}, targetKey=${targetKey}, typeKey=${typeKey}`);
    // Clear existing relations for this record
    console.log(`[RelationUtils] Clearing existing M2A relations in ${junctionTable}`);
    await dbOrTx.execute(sql `
    DELETE FROM "${sql.raw(junctionTable)}"
    WHERE "${sql.raw(sourceKey)}" = ${parentId}
  `);
    // Create new polymorphic junction records
    if (value.length > 0) {
        console.log(`[RelationUtils] Creating ${value.length} M2A junction records`);
        for (const item of value) {
            // Extract the target type and ID
            const targetType = item.type || item.collection;
            const targetId = item.item_id || item.item || item.id;
            if (!targetType || !targetId) {
                console.warn(`[RelationUtils] Skipping invalid M2A item:`, item);
                continue;
            }
            console.log(`[RelationUtils] Creating M2A junction: ${sourceKey}=${parentId}, ${typeKey}=${targetType}, ${targetKey}=${targetId}`);
            await dbOrTx.execute(sql `
        INSERT INTO "${sql.raw(junctionTable)}" ("${sql.raw(sourceKey)}", "${sql.raw(typeKey)}", "${sql.raw(targetKey)}")
        VALUES (${parentId}, ${targetType}, ${targetId})
      `);
        }
    }
    console.log(`[RelationUtils] Completed M2A relationship: ${association}`);
}
/**
 * Handle related records before delete.
 *
 * Regular relations (HasMany, HasOne, M2M) rely on DB FK constraints for cascade.
 * M2A targets need app-level cleanup because the polymorphic `item_id` column
 * in the junction table has no real DB FK (it references multiple tables).
 *
 * Scans all associations to find M2A sources whose `tables` array includes
 * the collection being deleted, then removes the corresponding junction rows.
 */
export async function handleRelatedRecordsBeforeDelete(item, service, transaction) {
    const collection = service.collection;
    const parentId = item[service.primaryKey];
    if (parentId == null)
        return;
    // O(1) lookup via reverse index — skips collections with no M2A references
    const junctions = relationBuilder.getM2AJunctionsForTarget(collection);
    if (junctions.length === 0)
        return;
    const { schemaManager } = await import('./schemaManager.js');
    const dbOrTx = transaction || getDatabase();
    for (const { model } of junctions) {
        const junctionTable = schemaManager.getTable(model);
        if (!junctionTable)
            continue;
        const itemIdCol = junctionTable['item_id'];
        const collectionCol = junctionTable['collection'];
        if (!itemIdCol || !collectionCol)
            continue;
        await dbOrTx.delete(junctionTable).where(and(eq(itemIdCol, parentId), eq(collectionCol, collection)));
    }
}
/**
 * Validate relational data - ensures referenced records exist
 */
export async function validateRelationalData(data, collection, service) {
    console.log(`[RelationUtils] Validating relational data for ${collection}`);
    const associations = relationBuilder.getAssociations(collection);
    if (!associations) {
        return;
    }
    const errors = [];
    for (const [key, value] of Object.entries(data)) {
        const association = associations[key];
        if (!association || value == null)
            continue;
        try {
            await validateRelation(association, key, value, service);
        }
        catch (error) {
            errors.push({ field: key, message: error.message });
        }
    }
    if (errors.length > 0) {
        const { APIError } = await import('./errorHandler.js');
        throw new APIError('Validation failed for relational data', 400, errors);
    }
}
/**
 * Validate a single relation - check if referenced records exist
 */
async function validateRelation(association, fieldName, value, service) {
    // Dynamically import ItemsService to avoid circular dependency
    const { default: ItemsService } = await import('../services/ItemsService.js');
    const relatedService = new ItemsService(association.model, {
        accountability: service.accountability,
        tenant: service.tenant
    });
    switch (association.type) {
        case 'BelongsTo':
            if (typeof value === 'object' && !value.id) {
                // New record to be created - validate will happen during create
                return;
            }
            else {
                const id = typeof value === 'object' ? value.id : value;
                try {
                    await relatedService.readOne(id, {}, true); // bypassPermissions
                }
                catch (error) {
                    throw new Error(`Related record not found: ${id}`);
                }
            }
            break;
        case 'HasMany':
        case 'BelongsToMany':
            if (!Array.isArray(value)) {
                throw new Error(`Value must be an array for ${fieldName}`);
            }
            for (const item of value) {
                if (typeof item === 'object' && !item.id) {
                    // New record to be created - validation will happen during create
                    continue;
                }
                const id = typeof item === 'object' ? item.id : item;
                try {
                    await relatedService.readOne(id, {}, true); // bypassPermissions
                }
                catch (error) {
                    throw new Error(`Related record not found: ${id}`);
                }
            }
            break;
    }
}
/**
 * Resolve circular dependencies in data
 * Detects BelongsTo relations that reference the parent record being created
 */
export async function resolveCircularDependencies(data, collection, service) {
    console.log(`[RelationUtils] Resolving circular dependencies for ${collection}`);
    const associations = relationBuilder.getAssociations(collection);
    if (!associations) {
        return { resolvedData: data, deferredFields: [] };
    }
    const resolvedData = { ...data };
    const deferredFields = [];
    for (const [key, value] of Object.entries(data)) {
        const association = associations[key];
        if (!association || value == null)
            continue;
        if (hasCircularDependency(association, value, service.primaryKey)) {
            console.log(`[RelationUtils] Found circular dependency in ${key}`);
            deferredFields.push({ field: key, value });
            delete resolvedData[key];
        }
    }
    console.log(`[RelationUtils] Resolved ${deferredFields.length} circular dependencies`);
    return { resolvedData, deferredFields };
}
/**
 * Check if a value has circular dependency
 * A circular dependency occurs when a BelongsTo relation references the parent's primary key
 */
function hasCircularDependency(association, value, primaryKey) {
    if (association.type !== 'BelongsTo')
        return false;
    // Check if the value is an object that references the parent's primary key
    // This happens when creating a record that has a BelongsTo pointing back to itself
    return typeof value === 'object' && !value.id && value[primaryKey];
}
/**
 * Process deferred fields after main record creation
 * Updates related records to link back to the newly created parent
 */
export async function processDeferredFields(item, deferredFields, service, transaction) {
    if (deferredFields.length === 0)
        return;
    console.log(`[RelationUtils] Processing ${deferredFields.length} deferred fields`);
    const associations = relationBuilder.getAssociations(service.collection);
    if (!associations)
        return;
    // Dynamically import ItemsService to avoid circular dependency
    const { default: ItemsService } = await import('../services/ItemsService.js');
    for (const { field, value } of deferredFields) {
        const association = associations[field];
        if (!association)
            continue;
        // Create a service for the related model
        const relatedService = new ItemsService(association.model, {
            accountability: service.accountability,
            tenant: service.tenant
        });
        // Update the related record to link to the new parent
        const foreignKey = association.foreignKey || `${field}_Id`;
        if (value[service.primaryKey]) {
            console.log(`[RelationUtils] Updating deferred ${field}: setting ${foreignKey} = ${item[service.primaryKey]}`);
            await relatedService.updateOne(value[service.primaryKey], { [foreignKey]: item[service.primaryKey] }, { transaction, bypassPermissions: true });
        }
    }
}
//# sourceMappingURL=relationUtils.js.map