import { jsx } from "react/jsx-runtime";
import { createContext, useState, useEffect } from "@wordpress/element";
import { privateApis as blockEditorPrivateApis } from "@wordpress/block-editor";
import { useSelect, useDispatch } from "@wordpress/data";
import {
  useEntityRecord,
  useEntityRecords,
  store as coreStore
} from "@wordpress/core-data";
import { __ } from "@wordpress/i18n";
import {
  fetchGetFontFamilyBySlug,
  fetchInstallFontFamily,
  fetchUninstallFontFamily,
  fetchFontCollections,
  fetchFontCollection
} from "./resolvers";
import { unlock } from "../../../lock-unlock";
const { useGlobalSetting } = unlock(blockEditorPrivateApis);
import {
  setUIValuesNeeded,
  mergeFontFamilies,
  loadFontFaceInBrowser,
  unloadFontFaceInBrowser,
  getDisplaySrcFromFontFace,
  makeFontFacesFormData,
  makeFontFamilyFormData,
  batchInstallFontFaces,
  checkFontFaceInstalled
} from "./utils";
import { toggleFont } from "./utils/toggleFont";
import setNestedValue from "../../../utils/set-nested-value";
const FontLibraryContext = createContext({});
FontLibraryContext.displayName = "FontLibraryContext";
function FontLibraryProvider({ children }) {
  const { saveEntityRecord } = useDispatch(coreStore);
  const { globalStylesId } = useSelect((select) => {
    const { __experimentalGetCurrentGlobalStylesId } = select(coreStore);
    return { globalStylesId: __experimentalGetCurrentGlobalStylesId() };
  });
  const globalStyles = useEntityRecord(
    "root",
    "globalStyles",
    globalStylesId
  );
  const [isInstalling, setIsInstalling] = useState(false);
  const [refreshKey, setRefreshKey] = useState(0);
  const refreshLibrary = () => {
    setRefreshKey(Date.now());
  };
  const { records: libraryPosts = [], isResolving: isResolvingLibrary } = useEntityRecords("postType", "wp_font_family", {
    refreshKey,
    _embed: true
  });
  const libraryFonts = (libraryPosts || []).map((fontFamilyPost) => {
    return {
      id: fontFamilyPost.id,
      ...fontFamilyPost.font_family_settings,
      fontFace: fontFamilyPost?._embedded?.font_faces.map(
        (face) => face.font_face_settings
      ) || []
    };
  }) || [];
  const [fontFamilies, setFontFamilies] = useGlobalSetting(
    "typography.fontFamilies"
  );
  const saveFontFamilies = async (fonts) => {
    const updatedGlobalStyles = globalStyles.record;
    setNestedValue(
      updatedGlobalStyles,
      ["settings", "typography", "fontFamilies"],
      fonts
    );
    await saveEntityRecord("root", "globalStyles", updatedGlobalStyles);
  };
  const [modalTabOpen, setModalTabOpen] = useState(false);
  const [libraryFontSelected, setLibraryFontSelected] = useState(null);
  const themeFonts = fontFamilies?.theme ? fontFamilies.theme.map((f) => setUIValuesNeeded(f, { source: "theme" })).sort((a, b) => a.name.localeCompare(b.name)) : [];
  const customFonts = fontFamilies?.custom ? fontFamilies.custom.map((f) => setUIValuesNeeded(f, { source: "custom" })).sort((a, b) => a.name.localeCompare(b.name)) : [];
  const baseCustomFonts = libraryFonts ? libraryFonts.map((f) => setUIValuesNeeded(f, { source: "custom" })).sort((a, b) => a.name.localeCompare(b.name)) : [];
  useEffect(() => {
    if (!modalTabOpen) {
      setLibraryFontSelected(null);
    }
  }, [modalTabOpen]);
  const handleSetLibraryFontSelected = (font) => {
    if (!font) {
      setLibraryFontSelected(null);
      return;
    }
    const fonts = font.source === "theme" ? themeFonts : baseCustomFonts;
    const fontSelected = fonts.find((f) => f.slug === font.slug);
    setLibraryFontSelected({
      ...fontSelected || font,
      source: font.source
    });
  };
  const [loadedFontUrls] = useState(/* @__PURE__ */ new Set());
  const getAvailableFontsOutline = (availableFontFamilies) => {
    const outline = availableFontFamilies.reduce((acc, font) => {
      const availableFontFaces = font?.fontFace && font.fontFace?.length > 0 ? font?.fontFace.map(
        (face) => `${face.fontStyle + face.fontWeight}`
      ) : ["normal400"];
      acc[font.slug] = availableFontFaces;
      return acc;
    }, {});
    return outline;
  };
  const getActivatedFontsOutline = (source) => {
    switch (source) {
      case "theme":
        return getAvailableFontsOutline(themeFonts);
      case "custom":
      default:
        return getAvailableFontsOutline(customFonts);
    }
  };
  const isFontActivated = (slug, style, weight, source) => {
    if (!style && !weight) {
      return !!getActivatedFontsOutline(source)[slug];
    }
    return !!getActivatedFontsOutline(source)[slug]?.includes(
      style + weight
    );
  };
  const getFontFacesActivated = (slug, source) => {
    return getActivatedFontsOutline(source)[slug] || [];
  };
  async function installFonts(fontFamiliesToInstall) {
    setIsInstalling(true);
    try {
      const fontFamiliesToActivate = [];
      let installationErrors = [];
      for (const fontFamilyToInstall of fontFamiliesToInstall) {
        let isANewFontFamily = false;
        let installedFontFamily = await fetchGetFontFamilyBySlug(
          fontFamilyToInstall.slug
        );
        if (!installedFontFamily) {
          isANewFontFamily = true;
          installedFontFamily = await fetchInstallFontFamily(
            makeFontFamilyFormData(fontFamilyToInstall)
          );
        }
        const alreadyInstalledFontFaces = installedFontFamily.fontFace && fontFamilyToInstall.fontFace ? installedFontFamily.fontFace.filter(
          (fontFaceToInstall) => checkFontFaceInstalled(
            fontFaceToInstall,
            fontFamilyToInstall.fontFace
          )
        ) : [];
        if (installedFontFamily.fontFace && fontFamilyToInstall.fontFace) {
          fontFamilyToInstall.fontFace = fontFamilyToInstall.fontFace.filter(
            (fontFaceToInstall) => !checkFontFaceInstalled(
              fontFaceToInstall,
              installedFontFamily.fontFace
            )
          );
        }
        let successfullyInstalledFontFaces = [];
        let unsuccessfullyInstalledFontFaces = [];
        if (fontFamilyToInstall?.fontFace?.length > 0) {
          const response = await batchInstallFontFaces(
            installedFontFamily.id,
            makeFontFacesFormData(fontFamilyToInstall)
          );
          successfullyInstalledFontFaces = response?.successes;
          unsuccessfullyInstalledFontFaces = response?.errors;
        }
        if (successfullyInstalledFontFaces?.length > 0 || alreadyInstalledFontFaces?.length > 0) {
          installedFontFamily.fontFace = [
            ...successfullyInstalledFontFaces
          ];
          fontFamiliesToActivate.push(installedFontFamily);
        }
        if (installedFontFamily && !fontFamilyToInstall?.fontFace?.length) {
          fontFamiliesToActivate.push(installedFontFamily);
        }
        if (isANewFontFamily && fontFamilyToInstall?.fontFace?.length > 0 && successfullyInstalledFontFaces?.length === 0) {
          await fetchUninstallFontFamily(installedFontFamily.id);
        }
        installationErrors = installationErrors.concat(
          unsuccessfullyInstalledFontFaces
        );
      }
      installationErrors = installationErrors.reduce(
        (unique, item) => unique.includes(item.message) ? unique : [...unique, item.message],
        []
      );
      if (fontFamiliesToActivate.length > 0) {
        const activeFonts = activateCustomFontFamilies(
          fontFamiliesToActivate
        );
        await saveFontFamilies(activeFonts);
        refreshLibrary();
      }
      if (installationErrors.length > 0) {
        const installError = new Error(
          __("There was an error installing fonts.")
        );
        installError.installationErrors = installationErrors;
        throw installError;
      }
    } finally {
      setIsInstalling(false);
    }
  }
  async function uninstallFontFamily(fontFamilyToUninstall) {
    try {
      const uninstalledFontFamily = await fetchUninstallFontFamily(
        fontFamilyToUninstall.id
      );
      if (uninstalledFontFamily.deleted) {
        const activeFonts = deactivateFontFamily(
          fontFamilyToUninstall
        );
        await saveFontFamilies(activeFonts);
      }
      refreshLibrary();
      return uninstalledFontFamily;
    } catch (error) {
      console.error(
        `There was an error uninstalling the font family:`,
        error
      );
      throw error;
    }
  }
  const deactivateFontFamily = (font) => {
    const initialCustomFonts = fontFamilies?.[font.source] ?? [];
    const newCustomFonts = initialCustomFonts.filter(
      (f) => f.slug !== font.slug
    );
    const activeFonts = {
      ...fontFamilies,
      [font.source]: newCustomFonts
    };
    setFontFamilies(activeFonts);
    if (font.fontFace) {
      font.fontFace.forEach((face) => {
        unloadFontFaceInBrowser(face, "all");
      });
    }
    return activeFonts;
  };
  const activateCustomFontFamilies = (fontsToAdd) => {
    const fontsToActivate = cleanFontsForSave(fontsToAdd);
    const activeFonts = {
      ...fontFamilies,
      // Merge the existing custom fonts with the new fonts.
      custom: mergeFontFamilies(fontFamilies?.custom, fontsToActivate)
    };
    setFontFamilies(activeFonts);
    loadFontsInBrowser(fontsToActivate);
    return activeFonts;
  };
  const cleanFontsForSave = (fonts) => {
    return fonts.map(({ id: _familyDbId, fontFace, ...font }) => ({
      ...font,
      ...fontFace && fontFace.length > 0 ? {
        fontFace: fontFace.map(
          ({ id: _faceDbId, ...face }) => face
        )
      } : {}
    }));
  };
  const loadFontsInBrowser = (fonts) => {
    fonts.forEach((font) => {
      if (font.fontFace) {
        font.fontFace.forEach((face) => {
          loadFontFaceInBrowser(
            face,
            getDisplaySrcFromFontFace(face.src),
            "all"
          );
        });
      }
    });
  };
  const toggleActivateFont = (font, face) => {
    const initialFonts = fontFamilies?.[font.source] ?? [];
    const newFonts = toggleFont(font, face, initialFonts);
    setFontFamilies({
      ...fontFamilies,
      [font.source]: newFonts
    });
    const isFaceActivated = isFontActivated(
      font.slug,
      face?.fontStyle,
      face?.fontWeight,
      font.source
    );
    if (isFaceActivated) {
      unloadFontFaceInBrowser(face, "all");
    } else {
      loadFontFaceInBrowser(
        face,
        getDisplaySrcFromFontFace(face?.src),
        "all"
      );
    }
  };
  const loadFontFaceAsset = async (fontFace) => {
    if (!fontFace.src) {
      return;
    }
    const src = getDisplaySrcFromFontFace(fontFace.src);
    if (!src || loadedFontUrls.has(src)) {
      return;
    }
    loadFontFaceInBrowser(fontFace, src, "document");
    loadedFontUrls.add(src);
  };
  const [collections, setFontCollections] = useState([]);
  const getFontCollections = async () => {
    const response = await fetchFontCollections();
    setFontCollections(response);
  };
  const getFontCollection = async (slug) => {
    try {
      const hasData = !!collections.find(
        (collection) => collection.slug === slug
      )?.font_families;
      if (hasData) {
        return;
      }
      const response = await fetchFontCollection(slug);
      const updatedCollections = collections.map(
        (collection) => collection.slug === slug ? { ...collection, ...response } : collection
      );
      setFontCollections(updatedCollections);
    } catch (e) {
      console.error(e);
      throw e;
    }
  };
  useEffect(() => {
    getFontCollections();
  }, []);
  return /* @__PURE__ */ jsx(
    FontLibraryContext.Provider,
    {
      value: {
        libraryFontSelected,
        handleSetLibraryFontSelected,
        fontFamilies,
        baseCustomFonts,
        isFontActivated,
        getFontFacesActivated,
        loadFontFaceAsset,
        installFonts,
        uninstallFontFamily,
        toggleActivateFont,
        getAvailableFontsOutline,
        modalTabOpen,
        setModalTabOpen,
        refreshLibrary,
        saveFontFamilies,
        isResolvingLibrary,
        isInstalling,
        collections,
        getFontCollection
      },
      children
    }
  );
}
var context_default = FontLibraryProvider;
export {
  FontLibraryContext,
  context_default as default
};
//# sourceMappingURL=context.js.map
