import * as devalue from "devalue";
import { pathToFileURL } from "url";
import { normalizePath } from "vite";
import { AstroErrorData } from "../core/errors/errors-data.js";
import { AstroError } from "../core/errors/errors.js";
import { escapeViteEnvReferences, getFileInfo } from "../vite-plugin-utils/index.js";
import { contentFileExts, CONTENT_FLAG } from "./consts.js";
import {
  extractFrontmatterAssets,
  getContentPaths,
  getEntryData,
  getEntryInfo,
  getEntrySlug,
  getEntryType,
  globalContentConfigObserver,
  parseFrontmatter
} from "./utils.js";
function isContentFlagImport(viteId) {
  const { pathname, searchParams } = new URL(viteId, "file://");
  return searchParams.has(CONTENT_FLAG) && contentFileExts.some((ext) => pathname.endsWith(ext));
}
function astroContentImportPlugin({
  fs,
  settings
}) {
  const contentPaths = getContentPaths(settings.config, fs);
  return {
    name: "astro:content-imports",
    async load(id) {
      const { fileId } = getFileInfo(id, settings.config);
      if (isContentFlagImport(id)) {
        const observable = globalContentConfigObserver.get();
        if (observable.status === "init") {
          throw new AstroError({
            ...AstroErrorData.UnknownContentCollectionError,
            message: "Content config failed to load."
          });
        }
        if (observable.status === "error") {
          throw observable.error;
        }
        let contentConfig = observable.status === "loaded" ? observable.config : void 0;
        if (observable.status === "loading") {
          contentConfig = await new Promise((resolve) => {
            const unsubscribe = globalContentConfigObserver.subscribe((ctx) => {
              if (ctx.status === "loaded") {
                resolve(ctx.config);
                unsubscribe();
              } else if (ctx.status === "error") {
                resolve(void 0);
                unsubscribe();
              }
            });
          });
        }
        const rawContents = await fs.promises.readFile(fileId, "utf-8");
        const {
          content: body,
          data: unparsedData,
          matter: rawData = ""
        } = parseFrontmatter(rawContents, fileId);
        const entryInfo = getEntryInfo({
          entry: pathToFileURL(fileId),
          contentDir: contentPaths.contentDir
        });
        if (entryInfo instanceof Error)
          return;
        const _internal = { filePath: fileId, rawData };
        const partialEntry = { data: unparsedData, body, _internal, ...entryInfo };
        const slug = getEntrySlug(partialEntry);
        const collectionConfig = contentConfig == null ? void 0 : contentConfig.collections[entryInfo.collection];
        const data = collectionConfig ? await getEntryData(partialEntry, collectionConfig) : unparsedData;
        const images = extractFrontmatterAssets(data).map(
          (image) => `'${image}': await import('${normalizePath(image)}'),`
        );
        const code = escapeViteEnvReferences(`
export const id = ${JSON.stringify(entryInfo.id)};
export const collection = ${JSON.stringify(entryInfo.collection)};
export const slug = ${JSON.stringify(slug)};
export const body = ${JSON.stringify(body)};
const frontmatterImages = {
	${images.join("\n")}
}
export const data = ${devalue.uneval(data)};
export const _internal = {
	filePath: ${JSON.stringify(fileId)},
	rawData: ${JSON.stringify(rawData)},
};
`);
        return { code };
      }
    },
    configureServer(viteServer) {
      viteServer.watcher.on("all", async (event, entry) => {
        if (["add", "unlink", "change"].includes(event) && getEntryType(entry, contentPaths) === "config") {
          for (const modUrl of viteServer.moduleGraph.urlToModuleMap.keys()) {
            if (isContentFlagImport(modUrl)) {
              const mod = await viteServer.moduleGraph.getModuleByUrl(modUrl);
              if (mod) {
                viteServer.moduleGraph.invalidateModule(mod);
              }
            }
          }
        }
      });
    },
    async transform(code, id) {
      if (isContentFlagImport(id)) {
        return { code: escapeViteEnvReferences(code) };
      }
    }
  };
}
export {
  astroContentImportPlugin
};
