import executeAccess from '../../auth/executeAccess.js';
import { combineQueries } from '../../database/combineQueries.js';
import { validateQueryPaths } from '../../database/queryValidation/validateQueryPaths.js';
import { sanitizeJoinQuery } from '../../database/sanitizeJoinQuery.js';
import { afterRead } from '../../fields/hooks/afterRead/index.js';
import { killTransaction } from '../../utilities/killTransaction.js';
import { buildVersionCollectionFields } from '../../versions/buildCollectionFields.js';
import { appendVersionToQueryKey } from '../../versions/drafts/appendVersionToQueryKey.js';
import { getQueryDraftsSelect } from '../../versions/drafts/getQueryDraftsSelect.js';
import { getQueryDraftsSort } from '../../versions/drafts/getQueryDraftsSort.js';
import { buildAfterOperation } from './utils.js';
export const findOperation = async (incomingArgs)=>{
    let args = incomingArgs;
    try {
        // /////////////////////////////////////
        // 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: 'read',
                req: args.req
            }) || args;
        }, Promise.resolve());
        const { collection: { config: collectionConfig }, collection, currentDepth, depth, disableErrors, draft: draftsEnabled, includeLockStatus, joins, limit, overrideAccess, page, pagination = true, populate, req: { fallbackLocale, locale, payload }, req, select, showHiddenFields, sort, where } = args;
        // /////////////////////////////////////
        // Access
        // /////////////////////////////////////
        let accessResult;
        if (!overrideAccess) {
            accessResult = await executeAccess({
                disableErrors,
                req
            }, collectionConfig.access.read);
            // If errors are disabled, and access returns false, return empty results
            if (accessResult === false) {
                return {
                    docs: [],
                    hasNextPage: false,
                    hasPrevPage: false,
                    limit,
                    nextPage: null,
                    page: 1,
                    pagingCounter: 1,
                    prevPage: null,
                    totalDocs: 0,
                    totalPages: 1
                };
            }
        }
        // /////////////////////////////////////
        // Find
        // /////////////////////////////////////
        const usePagination = pagination && limit !== 0;
        const sanitizedLimit = limit ?? (usePagination ? 10 : 0);
        const sanitizedPage = page || 1;
        let result;
        let fullWhere = combineQueries(where, accessResult);
        const sanitizedJoins = await sanitizeJoinQuery({
            collectionConfig,
            joins,
            overrideAccess,
            req
        });
        if (collectionConfig.versions?.drafts && draftsEnabled) {
            fullWhere = appendVersionToQueryKey(fullWhere);
            await validateQueryPaths({
                collectionConfig: collection.config,
                overrideAccess,
                req,
                versionFields: buildVersionCollectionFields(payload.config, collection.config),
                where: fullWhere
            });
            result = await payload.db.queryDrafts({
                collection: collectionConfig.slug,
                joins: req.payloadAPI === 'GraphQL' ? false : sanitizedJoins,
                limit: sanitizedLimit,
                locale,
                page: sanitizedPage,
                pagination: usePagination,
                req,
                select: getQueryDraftsSelect({
                    select
                }),
                sort: getQueryDraftsSort({
                    collectionConfig,
                    sort
                }),
                where: fullWhere
            });
        } else {
            await validateQueryPaths({
                collectionConfig,
                overrideAccess,
                req,
                where
            });
            result = await payload.db.find({
                collection: collectionConfig.slug,
                joins: req.payloadAPI === 'GraphQL' ? false : sanitizedJoins,
                limit: sanitizedLimit,
                locale,
                page: sanitizedPage,
                pagination,
                req,
                select,
                sort,
                where: fullWhere
            });
        }
        if (includeLockStatus) {
            try {
                const lockDocumentsProp = collectionConfig?.lockDocuments;
                const lockDurationDefault = 300 // Default 5 minutes in seconds
                ;
                const lockDuration = typeof lockDocumentsProp === 'object' ? lockDocumentsProp.duration : lockDurationDefault;
                const lockDurationInMilliseconds = lockDuration * 1000;
                const lockedDocuments = await payload.find({
                    collection: 'payload-locked-documents',
                    depth: 1,
                    limit: sanitizedLimit,
                    overrideAccess: false,
                    pagination: false,
                    req,
                    where: {
                        and: [
                            {
                                'document.relationTo': {
                                    equals: collectionConfig.slug
                                }
                            },
                            {
                                'document.value': {
                                    in: result.docs.map((doc)=>doc.id)
                                }
                            },
                            // Query where the lock is newer than the current time minus lock time
                            {
                                updatedAt: {
                                    greater_than: new Date(new Date().getTime() - lockDurationInMilliseconds)
                                }
                            }
                        ]
                    }
                });
                const now = new Date().getTime();
                const lockedDocs = Array.isArray(lockedDocuments?.docs) ? lockedDocuments.docs : [];
                // Filter out stale locks
                const validLockedDocs = lockedDocs.filter((lock)=>{
                    const lastEditedAt = new Date(lock?.updatedAt).getTime();
                    return lastEditedAt + lockDurationInMilliseconds > now;
                });
                result.docs = result.docs.map((doc)=>{
                    const lockedDoc = validLockedDocs.find((lock)=>lock?.document?.value === doc.id);
                    return {
                        ...doc,
                        _isLocked: !!lockedDoc,
                        _userEditing: lockedDoc ? lockedDoc?.user?.value : null
                    };
                });
            } catch (error) {
                result.docs = result.docs.map((doc)=>({
                        ...doc,
                        _isLocked: false,
                        _userEditing: null
                    }));
            }
        }
        // /////////////////////////////////////
        // beforeRead - Collection
        // /////////////////////////////////////
        result = {
            ...result,
            docs: await Promise.all(result.docs.map(async (doc)=>{
                let docRef = doc;
                await collectionConfig.hooks.beforeRead.reduce(async (priorHook, hook)=>{
                    await priorHook;
                    docRef = await hook({
                        collection: collectionConfig,
                        context: req.context,
                        doc: docRef,
                        query: fullWhere,
                        req
                    }) || docRef;
                }, Promise.resolve());
                return docRef;
            }))
        };
        // /////////////////////////////////////
        // afterRead - Fields
        // /////////////////////////////////////
        result = {
            ...result,
            docs: await Promise.all(result.docs.map(async (doc)=>afterRead({
                    collection: collectionConfig,
                    context: req.context,
                    currentDepth,
                    depth,
                    doc,
                    draft: draftsEnabled,
                    fallbackLocale,
                    findMany: true,
                    global: null,
                    locale,
                    overrideAccess,
                    populate,
                    req,
                    select,
                    showHiddenFields
                })))
        };
        // /////////////////////////////////////
        // afterRead - Collection
        // /////////////////////////////////////
        result = {
            ...result,
            docs: await Promise.all(result.docs.map(async (doc)=>{
                let docRef = doc;
                await collectionConfig.hooks.afterRead.reduce(async (priorHook, hook)=>{
                    await priorHook;
                    docRef = await hook({
                        collection: collectionConfig,
                        context: req.context,
                        doc: docRef,
                        findMany: true,
                        query: fullWhere,
                        req
                    }) || doc;
                }, Promise.resolve());
                return docRef;
            }))
        };
        // /////////////////////////////////////
        // afterOperation - Collection
        // /////////////////////////////////////
        result = await buildAfterOperation({
            args,
            collection: collectionConfig,
            operation: 'find',
            result
        });
        // /////////////////////////////////////
        // Return results
        // /////////////////////////////////////
        return result;
    } catch (error) {
        await killTransaction(args.req);
        throw error;
    }
};

//# sourceMappingURL=find.js.map