import httpStatus from 'http-status';
import executeAccess from '../../auth/executeAccess.js';
import { combineQueries } from '../../database/combineQueries.js';
import { validateQueryPaths } from '../../database/queryValidation/validateQueryPaths.js';
import { APIError } from '../../errors/index.js';
import { afterChange } from '../../fields/hooks/afterChange/index.js';
import { afterRead } from '../../fields/hooks/afterRead/index.js';
import { beforeChange } from '../../fields/hooks/beforeChange/index.js';
import { beforeValidate } from '../../fields/hooks/beforeValidate/index.js';
import { deleteAssociatedFiles } from '../../uploads/deleteAssociatedFiles.js';
import { generateFileData } from '../../uploads/generateFileData.js';
import { unlinkTempFiles } from '../../uploads/unlinkTempFiles.js';
import { uploadFiles } from '../../uploads/uploadFiles.js';
import { commitTransaction } from '../../utilities/commitTransaction.js';
import { initTransaction } from '../../utilities/initTransaction.js';
import { killTransaction } from '../../utilities/killTransaction.js';
import { buildVersionCollectionFields } from '../../versions/buildCollectionFields.js';
import { appendVersionToQueryKey } from '../../versions/drafts/appendVersionToQueryKey.js';
import { saveVersion } from '../../versions/saveVersion.js';
import { buildAfterOperation } from './utils.js';
export const updateOperation = async (incomingArgs)=>{
    let args = incomingArgs;
    try {
        const shouldCommit = await initTransaction(args.req);
        // /////////////////////////////////////
        // beforeOperation - Collection
        // /////////////////////////////////////
        await args.collection.config.hooks.beforeOperation.reduce(async (priorHook, hook)=>{
            await priorHook;
            args = await hook({
                args,
                collection: args.collection.config,
                context: args.req.context,
                operation: 'update',
                req: args.req
            }) || args;
        }, Promise.resolve());
        const { collection: { config: collectionConfig }, collection, depth, draft: draftArg = false, overrideAccess, overwriteExistingFiles = false, req: { fallbackLocale, locale, payload: { config }, payload }, req, showHiddenFields, where } = args;
        if (!where) {
            throw new APIError("Missing 'where' query of documents to update.", httpStatus.BAD_REQUEST);
        }
        const { data: bulkUpdateData } = args;
        const shouldSaveDraft = Boolean(draftArg && collectionConfig.versions.drafts);
        // /////////////////////////////////////
        // Access
        // /////////////////////////////////////
        let accessResult;
        if (!overrideAccess) {
            accessResult = await executeAccess({
                req
            }, collectionConfig.access.update);
        }
        await validateQueryPaths({
            collectionConfig,
            overrideAccess,
            req,
            where
        });
        // /////////////////////////////////////
        // Retrieve documents
        // /////////////////////////////////////
        const fullWhere = combineQueries(where, accessResult);
        let docs;
        if (collectionConfig.versions?.drafts && shouldSaveDraft) {
            const versionsWhere = appendVersionToQueryKey(fullWhere);
            await validateQueryPaths({
                collectionConfig: collection.config,
                overrideAccess,
                req,
                versionFields: buildVersionCollectionFields(collection.config),
                where: versionsWhere
            });
            const query = await payload.db.queryDrafts({
                collection: collectionConfig.slug,
                locale,
                req,
                where: versionsWhere
            });
            docs = query.docs;
        } else {
            const query = await payload.db.find({
                collection: collectionConfig.slug,
                limit: 0,
                locale,
                pagination: false,
                req,
                where: fullWhere
            });
            docs = query.docs;
        }
        // /////////////////////////////////////
        // Generate data for all files and sizes
        // /////////////////////////////////////
        const { data: newFileData, files: filesToUpload } = await generateFileData({
            collection,
            config,
            data: bulkUpdateData,
            overwriteExistingFiles,
            req,
            throwOnMissingFile: false
        });
        const errors = [];
        const promises = docs.map(async (doc)=>{
            const { id } = doc;
            let data = {
                ...newFileData,
                ...bulkUpdateData
            };
            try {
                const originalDoc = await afterRead({
                    collection: collectionConfig,
                    context: req.context,
                    depth: 0,
                    doc,
                    fallbackLocale,
                    global: null,
                    locale,
                    overrideAccess: true,
                    req,
                    showHiddenFields: true
                });
                await deleteAssociatedFiles({
                    collectionConfig,
                    config,
                    doc,
                    files: filesToUpload,
                    overrideDelete: false,
                    req
                });
                // /////////////////////////////////////
                // beforeValidate - Fields
                // /////////////////////////////////////
                data = await beforeValidate({
                    id,
                    collection: collectionConfig,
                    context: req.context,
                    data,
                    doc: originalDoc,
                    global: null,
                    operation: 'update',
                    overrideAccess,
                    req
                });
                // /////////////////////////////////////
                // beforeValidate - Collection
                // /////////////////////////////////////
                await collectionConfig.hooks.beforeValidate.reduce(async (priorHook, hook)=>{
                    await priorHook;
                    data = await hook({
                        collection: collectionConfig,
                        context: req.context,
                        data,
                        operation: 'update',
                        originalDoc,
                        req
                    }) || data;
                }, Promise.resolve());
                // /////////////////////////////////////
                // Write files to local storage
                // /////////////////////////////////////
                if (!collectionConfig.upload.disableLocalStorage) {
                    await uploadFiles(payload, filesToUpload, req);
                }
                // /////////////////////////////////////
                // beforeChange - Collection
                // /////////////////////////////////////
                await collectionConfig.hooks.beforeChange.reduce(async (priorHook, hook)=>{
                    await priorHook;
                    data = await hook({
                        collection: collectionConfig,
                        context: req.context,
                        data,
                        operation: 'update',
                        originalDoc,
                        req
                    }) || data;
                }, Promise.resolve());
                // /////////////////////////////////////
                // beforeChange - Fields
                // /////////////////////////////////////
                let result = await beforeChange({
                    id,
                    collection: collectionConfig,
                    context: req.context,
                    data,
                    doc: originalDoc,
                    docWithLocales: doc,
                    global: null,
                    operation: 'update',
                    req,
                    skipValidation: shouldSaveDraft || data._status === 'draft'
                });
                // /////////////////////////////////////
                // Update
                // /////////////////////////////////////
                if (!shouldSaveDraft) {
                    result = await req.payload.db.updateOne({
                        id,
                        collection: collectionConfig.slug,
                        data: result,
                        locale,
                        req
                    });
                }
                // /////////////////////////////////////
                // Create version
                // /////////////////////////////////////
                if (collectionConfig.versions) {
                    result = await saveVersion({
                        id,
                        collection: collectionConfig,
                        docWithLocales: {
                            ...result,
                            createdAt: doc.createdAt
                        },
                        draft: shouldSaveDraft,
                        payload,
                        req
                    });
                }
                // /////////////////////////////////////
                // afterRead - Fields
                // /////////////////////////////////////
                result = await afterRead({
                    collection: collectionConfig,
                    context: req.context,
                    depth,
                    doc: result,
                    fallbackLocale: null,
                    global: null,
                    locale,
                    overrideAccess,
                    req,
                    showHiddenFields
                });
                // /////////////////////////////////////
                // afterRead - Collection
                // /////////////////////////////////////
                await collectionConfig.hooks.afterRead.reduce(async (priorHook, hook)=>{
                    await priorHook;
                    result = await hook({
                        collection: collectionConfig,
                        context: req.context,
                        doc: result,
                        req
                    }) || result;
                }, Promise.resolve());
                // /////////////////////////////////////
                // afterChange - Fields
                // /////////////////////////////////////
                result = await afterChange({
                    collection: collectionConfig,
                    context: req.context,
                    data,
                    doc: result,
                    global: null,
                    operation: 'update',
                    previousDoc: originalDoc,
                    req
                });
                // /////////////////////////////////////
                // afterChange - Collection
                // /////////////////////////////////////
                await collectionConfig.hooks.afterChange.reduce(async (priorHook, hook)=>{
                    await priorHook;
                    result = await hook({
                        collection: collectionConfig,
                        context: req.context,
                        doc: result,
                        operation: 'update',
                        previousDoc: originalDoc,
                        req
                    }) || result;
                }, Promise.resolve());
                await unlinkTempFiles({
                    collectionConfig,
                    config,
                    req
                });
                // /////////////////////////////////////
                // Return results
                // /////////////////////////////////////
                return result;
            } catch (error) {
                errors.push({
                    id,
                    message: error.message
                });
            }
            return null;
        });
        const awaitedDocs = await Promise.all(promises);
        let result = {
            docs: awaitedDocs.filter(Boolean),
            errors
        };
        // /////////////////////////////////////
        // afterOperation - Collection
        // /////////////////////////////////////
        result = await buildAfterOperation({
            args,
            collection: collectionConfig,
            operation: 'update',
            result
        });
        if (shouldCommit) await commitTransaction(req);
        return result;
    } catch (error) {
        await killTransaction(args.req);
        throw error;
    }
};

//# sourceMappingURL=update.js.map