'use client';

import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useModal } from '@faceless-ui/modal';
import * as qs from 'qs-esm';
import React from 'react';
import { toast } from 'sonner';
import { fieldReducer } from '../../../forms/Form/fieldReducer.js';
import { useEffectEvent } from '../../../hooks/useEffectEvent.js';
import { useConfig } from '../../../providers/Config/index.js';
import { useLocale } from '../../../providers/Locale/index.js';
import { useServerFunctions } from '../../../providers/ServerFunctions/index.js';
import { useTranslation } from '../../../providers/Translation/index.js';
import { useUploadHandlers } from '../../../providers/UploadHandlers/index.js';
import { hasSavePermission as getHasSavePermission } from '../../../utilities/hasSavePermission.js';
import { LoadingOverlay } from '../../Loading/index.js';
import { useLoadingOverlay } from '../../LoadingOverlay/index.js';
import { useBulkUpload } from '../index.js';
import { createFormData } from './createFormData.js';
import { formsManagementReducer } from './reducer.js';
const Context = /*#__PURE__*/React.createContext({
  activeIndex: 0,
  addFiles: () => Promise.resolve(),
  bulkUpdateForm: () => null,
  collectionSlug: '',
  docPermissions: undefined,
  documentSlots: {},
  forms: [],
  getFormDataRef: {
    current: () => ({})
  },
  hasPublishPermission: false,
  hasSavePermission: false,
  hasSubmitted: false,
  isInitializing: false,
  removeFile: () => {},
  saveAllDocs: () => Promise.resolve(),
  setActiveIndex: () => 0,
  setFormTotalErrorCount: () => {},
  totalErrorCount: 0,
  updateUploadEdits: () => {}
});
const initialState = {
  activeIndex: 0,
  forms: [],
  totalErrorCount: 0
};
export function FormsManagerProvider({
  children
}) {
  const {
    config
  } = useConfig();
  const {
    routes: {
      api
    },
    serverURL
  } = config;
  const {
    code
  } = useLocale();
  const {
    i18n,
    t
  } = useTranslation();
  const {
    getDocumentSlots,
    getFormState
  } = useServerFunctions();
  const {
    getUploadHandler
  } = useUploadHandlers();
  const [documentSlots, setDocumentSlots] = React.useState({});
  const [hasSubmitted, setHasSubmitted] = React.useState(false);
  const [docPermissions, setDocPermissions] = React.useState();
  const [hasSavePermission, setHasSavePermission] = React.useState(false);
  const [hasPublishPermission, setHasPublishPermission] = React.useState(false);
  const [hasInitializedState, setHasInitializedState] = React.useState(false);
  const [hasInitializedDocPermissions, setHasInitializedDocPermissions] = React.useState(false);
  const [isInitializing, setIsInitializing] = React.useState(false);
  const [state, dispatch] = React.useReducer(formsManagementReducer, initialState);
  const {
    activeIndex,
    forms,
    totalErrorCount
  } = state;
  const formsRef = React.useRef(forms);
  formsRef.current = forms;
  const {
    toggleLoadingOverlay
  } = useLoadingOverlay();
  const {
    closeModal
  } = useModal();
  const {
    collectionSlug,
    drawerSlug,
    initialFiles,
    initialForms,
    onSuccess,
    setInitialFiles,
    setInitialForms,
    setSuccessfullyUploaded
  } = useBulkUpload();
  const [isUploading, setIsUploading] = React.useState(false);
  const [loadingText, setLoadingText] = React.useState('');
  const hasInitializedWithFiles = React.useRef(false);
  const initialStateRef = React.useRef(null);
  const getFormDataRef = React.useRef(() => ({}));
  const actionURL = `${serverURL}${api}/${collectionSlug}`;
  const initializeSharedDocPermissions = React.useCallback(async () => {
    const params = {
      locale: code || undefined
    };
    const docAccessURL = `/${collectionSlug}/access`;
    const res = await fetch(`${serverURL}${api}${docAccessURL}?${qs.stringify(params)}`, {
      credentials: 'include',
      headers: {
        'Accept-Language': i18n.language,
        'Content-Type': 'application/json'
      },
      method: 'post'
    });
    const json = await res.json();
    const publishedAccessJSON = await fetch(`${serverURL}${api}${docAccessURL}?${qs.stringify(params)}`, {
      body: JSON.stringify({
        _status: 'published'
      }),
      credentials: 'include',
      headers: {
        'Accept-Language': i18n.language,
        'Content-Type': 'application/json'
      },
      method: 'POST'
    }).then(res_0 => res_0.json());
    setDocPermissions(json);
    setHasSavePermission(getHasSavePermission({
      collectionSlug,
      docPermissions: json,
      isEditing: false
    }));
    setHasPublishPermission(publishedAccessJSON?.update);
    setHasInitializedDocPermissions(true);
  }, [api, code, collectionSlug, i18n.language, serverURL]);
  const initializeSharedFormState = React.useCallback(async abortController => {
    if (abortController?.signal) {
      abortController.abort('aborting previous fetch for initial form state without files');
    }
    // FETCH AND SET THE DOCUMENT SLOTS HERE!
    const documentSlots_0 = await getDocumentSlots({
      collectionSlug
    });
    setDocumentSlots(documentSlots_0);
    try {
      const {
        state: formStateWithoutFiles
      } = await getFormState({
        collectionSlug,
        docPermissions,
        docPreferences: {
          fields: {}
        },
        locale: code,
        operation: 'create',
        renderAllFields: true,
        schemaPath: collectionSlug,
        skipValidation: true
      });
      initialStateRef.current = formStateWithoutFiles;
      setHasInitializedState(true);
    } catch (_err) {
      // swallow error
    }
  }, [getDocumentSlots, collectionSlug, getFormState, docPermissions, code]);
  const setActiveIndex = React.useCallback(index => {
    const currentFormsData = getFormDataRef.current();
    dispatch({
      type: 'REPLACE',
      state: {
        activeIndex: index,
        forms: forms.map((form, i) => {
          if (i === activeIndex) {
            return {
              errorCount: form.errorCount,
              formID: form.formID,
              formState: currentFormsData,
              uploadEdits: form.uploadEdits
            };
          }
          return form;
        })
      }
    });
  }, [forms, activeIndex]);
  const addFiles = React.useCallback(async files => {
    if (forms.length) {
      // save the state of the current form before adding new files
      dispatch({
        type: 'UPDATE_FORM',
        errorCount: forms[activeIndex].errorCount,
        formState: getFormDataRef.current(),
        index: activeIndex
      });
    }
    toggleLoadingOverlay({
      isLoading: true,
      key: 'addingDocs'
    });
    if (!hasInitializedState) {
      await initializeSharedFormState();
    }
    dispatch({
      type: 'ADD_FORMS',
      forms: Array.from(files).map(file => ({
        file,
        initialState: initialStateRef.current
      }))
    });
    toggleLoadingOverlay({
      isLoading: false,
      key: 'addingDocs'
    });
  }, [initializeSharedFormState, hasInitializedState, toggleLoadingOverlay, activeIndex, forms]);
  const addFilesEffectEvent = useEffectEvent(addFiles);
  const addInitialForms = useEffectEvent(async initialForms_0 => {
    toggleLoadingOverlay({
      isLoading: true,
      key: 'addingDocs'
    });
    if (!hasInitializedState) {
      await initializeSharedFormState();
    }
    dispatch({
      type: 'ADD_FORMS',
      forms: initialForms_0.map(form_0 => ({
        ...form_0,
        initialState: form_0?.initialState || initialStateRef.current
      }))
    });
    toggleLoadingOverlay({
      isLoading: false,
      key: 'addingDocs'
    });
  });
  const removeFile = React.useCallback(index_0 => {
    dispatch({
      type: 'REMOVE_FORM',
      index: index_0
    });
  }, []);
  const setFormTotalErrorCount = React.useCallback(({
    errorCount,
    index: index_1
  }) => {
    dispatch({
      type: 'UPDATE_ERROR_COUNT',
      count: errorCount,
      index: index_1
    });
  }, []);
  const saveAllDocs = React.useCallback(async ({
    overrides
  } = {}) => {
    const currentFormsData_0 = getFormDataRef.current();
    const currentForms = [...forms];
    currentForms[activeIndex] = {
      errorCount: currentForms[activeIndex].errorCount,
      formID: currentForms[activeIndex].formID,
      formState: currentFormsData_0,
      uploadEdits: currentForms[activeIndex].uploadEdits
    };
    const newDocs = [];
    setIsUploading(true);
    for (let i_0 = 0; i_0 < currentForms.length; i_0++) {
      try {
        const form_1 = currentForms[i_0];
        const fileValue = form_1.formState?.file?.value;
        // Skip upload if file is missing a filename
        if (fileValue && typeof fileValue === 'object' && 'name' in fileValue && (!fileValue.name || fileValue.name === '')) {
          currentForms[i_0] = {
            ...currentForms[i_0],
            errorCount: 1
          };
          continue;
        }
        setLoadingText(t('general:uploadingBulk', {
          current: i_0 + 1,
          total: currentForms.length
        }));
        const actionURLWithParams = `${actionURL}${qs.stringify({
          locale: code,
          uploadEdits: form_1?.uploadEdits || undefined
        }, {
          addQueryPrefix: true
        })}`;
        const req = await fetch(actionURLWithParams, {
          body: await createFormData(form_1.formState, overrides, collectionSlug, getUploadHandler({
            collectionSlug
          })),
          credentials: 'include',
          method: 'POST'
        });
        const json_0 = await req.json();
        if (req.status === 201 && json_0?.doc) {
          newDocs.push({
            collectionSlug,
            doc: json_0.doc,
            formID: form_1.formID
          });
        }
        // should expose some sort of helper for this
        const [fieldErrors, nonFieldErrors] = (json_0?.errors || []).reduce(([fieldErrs, nonFieldErrs], err) => {
          const newFieldErrs = [];
          const newNonFieldErrs = [];
          if (err?.message) {
            newNonFieldErrs.push(err);
          }
          if (Array.isArray(err?.data?.errors)) {
            err.data?.errors.forEach(dataError => {
              if (dataError?.path) {
                newFieldErrs.push(dataError);
              } else {
                newNonFieldErrs.push(dataError);
              }
            });
          }
          return [[...fieldErrs, ...newFieldErrs], [...nonFieldErrs, ...newNonFieldErrs]];
        }, [[], []]);
        currentForms[i_0] = {
          errorCount: fieldErrors.length,
          formID: currentForms[i_0].formID,
          formState: fieldReducer(currentForms[i_0].formState, {
            type: 'ADD_SERVER_ERRORS',
            errors: fieldErrors
          })
        };
        if (req.status === 413 || req.status === 400) {
          // file too large
          currentForms[i_0] = {
            ...currentForms[i_0],
            errorCount: currentForms[i_0].errorCount + 1
          };
          toast.error(nonFieldErrors[0]?.message);
        }
      } catch (_) {
        // swallow
      }
    }
    setHasSubmitted(true);
    setLoadingText('');
    setIsUploading(false);
    const remainingForms = [];
    currentForms.forEach(({
      errorCount: errorCount_0
    }, i_1) => {
      if (errorCount_0) {
        remainingForms.push(currentForms[i_1]);
      }
    });
    const successCount = Math.max(0, currentForms.length - remainingForms.length);
    const errorCount_1 = currentForms.length - successCount;
    if (successCount) {
      toast.success(`Successfully saved ${successCount} files`);
      setSuccessfullyUploaded(true);
      if (typeof onSuccess === 'function') {
        onSuccess(newDocs, errorCount_1);
      }
    }
    if (errorCount_1) {
      toast.error(`Failed to save ${errorCount_1} files`);
    } else {
      closeModal(drawerSlug);
    }
    dispatch({
      type: 'REPLACE',
      state: {
        activeIndex: 0,
        forms: remainingForms,
        totalErrorCount: remainingForms.reduce((acc, {
          errorCount: errorCount_2
        }) => acc + errorCount_2, 0)
      }
    });
    if (remainingForms.length === 0) {
      setInitialFiles(undefined);
      setInitialForms(undefined);
    }
  }, [forms, activeIndex, t, actionURL, code, collectionSlug, getUploadHandler, onSuccess, closeModal, setSuccessfullyUploaded, drawerSlug, setInitialFiles, setInitialForms]);
  const bulkUpdateForm = React.useCallback(async (updatedFields, afterStateUpdate) => {
    for (let i_2 = 0; i_2 < forms.length; i_2++) {
      Object.entries(updatedFields).forEach(([path, value]) => {
        if (forms[i_2].formState[path]) {
          forms[i_2].formState[path].value = value;
          dispatch({
            type: 'UPDATE_FORM',
            errorCount: forms[i_2].errorCount,
            formState: forms[i_2].formState,
            index: i_2
          });
        }
      });
      if (typeof afterStateUpdate === 'function') {
        afterStateUpdate();
      }
      if (hasSubmitted) {
        const {
          state: state_0
        } = await getFormState({
          collectionSlug,
          docPermissions,
          docPreferences: null,
          formState: forms[i_2].formState,
          operation: 'create',
          schemaPath: collectionSlug
        });
        const newFormErrorCount = Object.values(state_0).reduce((acc_0, value_0) => value_0?.valid === false ? acc_0 + 1 : acc_0, 0);
        dispatch({
          type: 'UPDATE_FORM',
          errorCount: newFormErrorCount,
          formState: state_0,
          index: i_2
        });
      }
    }
  }, [collectionSlug, docPermissions, forms, getFormState, hasSubmitted]);
  const updateUploadEdits = React.useCallback(uploadEdits => {
    dispatch({
      type: 'UPDATE_FORM',
      errorCount: forms[activeIndex].errorCount,
      formState: forms[activeIndex].formState,
      index: activeIndex,
      uploadEdits
    });
  }, [activeIndex, forms]);
  const resetUploadEdits = React.useCallback(() => {
    dispatch({
      type: 'REPLACE',
      state: {
        forms: forms.map(form_2 => ({
          ...form_2,
          uploadEdits: {}
        }))
      }
    });
  }, [forms]);
  React.useEffect(() => {
    if (!collectionSlug) {
      return;
    }
    if (!hasInitializedState) {
      void initializeSharedFormState();
    }
    if (!hasInitializedDocPermissions) {
      void initializeSharedDocPermissions();
    }
    if (initialFiles || initialForms) {
      if (!hasInitializedState || !hasInitializedDocPermissions) {
        setIsInitializing(true);
      } else {
        setIsInitializing(false);
      }
    }
    if (hasInitializedState && (initialForms?.length || initialFiles?.length) && !hasInitializedWithFiles.current) {
      if (initialForms?.length) {
        void addInitialForms(initialForms);
      }
      if (initialFiles?.length) {
        void addFilesEffectEvent(initialFiles);
      }
      hasInitializedWithFiles.current = true;
    }
    return;
  }, [initialFiles, initializeSharedFormState, initializeSharedDocPermissions, collectionSlug, hasInitializedState, hasInitializedDocPermissions, initialForms]);
  return /*#__PURE__*/_jsxs(Context, {
    value: {
      activeIndex: state.activeIndex,
      addFiles,
      bulkUpdateForm,
      collectionSlug,
      docPermissions,
      documentSlots,
      forms,
      getFormDataRef,
      hasPublishPermission,
      hasSavePermission,
      hasSubmitted,
      isInitializing,
      removeFile,
      resetUploadEdits,
      saveAllDocs,
      setActiveIndex,
      setFormTotalErrorCount,
      totalErrorCount,
      updateUploadEdits
    },
    children: [isUploading && /*#__PURE__*/_jsx(LoadingOverlay, {
      animationDuration: "250ms",
      loadingText: loadingText,
      overlayType: "fullscreen",
      show: true
    }), children]
  });
}
export function useFormsManager() {
  return React.use(Context);
}
//# sourceMappingURL=index.js.map