import MagicString from "magic-string";
import mime from "mime";
import fs from "node:fs/promises";
import path from "node:path";
import { Readable } from "node:stream";
import { fileURLToPath, pathToFileURL } from "node:url";
import { normalizePath } from "vite";
import { error } from "../core/logger/core.js";
import { joinPaths, prependForwardSlash } from "../core/path.js";
import { rootRelativePath } from "../core/util.js";
import { VIRTUAL_MODULE_ID, VIRTUAL_SERVICE_ID } from "./consts.js";
import { isESMImportedImage } from "./internal.js";
import { isLocalService } from "./services/service.js";
import { copyWasmFiles } from "./services/vendor/squoosh/copy-wasm.js";
import { imageMetadata } from "./utils/metadata.js";
import { getOrigQueryParams } from "./utils/queryParams.js";
import { propsToFilename } from "./utils/transformToPath.js";
const resolvedVirtualModuleId = "\0" + VIRTUAL_MODULE_ID;
function assets({
  settings,
  logging,
  mode
}) {
  let resolvedConfig;
  globalThis.astroAsset = {};
  return [
    {
      name: "astro:assets",
      config() {
        return {
          resolve: {
            alias: [
              {
                find: /^~\/assets\/(.+)$/,
                replacement: fileURLToPath(new URL("./assets/$1", settings.config.srcDir))
              }
            ]
          }
        };
      },
      async resolveId(id) {
        if (id === VIRTUAL_SERVICE_ID) {
          return await this.resolve(settings.config.image.service);
        }
        if (id === VIRTUAL_MODULE_ID) {
          return resolvedVirtualModuleId;
        }
      },
      load(id) {
        if (id === resolvedVirtualModuleId) {
          return `
					export { getImage, getConfiguredImageService } from "astro/assets";
					export { default as Image } from "astro/components/Image.astro";
				`;
        }
      },
      configureServer(server) {
        server.middlewares.use(async (req, res, next) => {
          var _a;
          if ((_a = req.url) == null ? void 0 : _a.startsWith("/_image")) {
            if (!isLocalService(globalThis.astroAsset.imageService)) {
              return next();
            }
            const url = new URL(req.url, "file:");
            const filePath = url.searchParams.get("href");
            if (!filePath) {
              return next();
            }
            const filePathURL = new URL(filePath, "file:");
            const file = await fs.readFile(filePathURL.pathname);
            let meta = getOrigQueryParams(filePathURL.searchParams);
            if (!meta) {
              meta = await imageMetadata(filePathURL, file);
              if (!meta) {
                return next();
              }
            }
            const transform = await globalThis.astroAsset.imageService.parseURL(url);
            if (transform === void 0) {
              error(logging, "image", `Failed to parse transform for ${url}`);
            }
            let data = file;
            let format = meta.format;
            if (transform) {
              const result = await globalThis.astroAsset.imageService.transform(file, transform);
              data = result.data;
              format = result.format;
            }
            res.setHeader("Content-Type", mime.getType(fileURLToPath(url)) || `image/${format}`);
            res.setHeader("Cache-Control", "max-age=360000");
            const stream = Readable.from(data);
            return stream.pipe(res);
          }
          return next();
        });
      },
      buildStart() {
        if (mode != "build") {
          return;
        }
        globalThis.astroAsset.addStaticImage = (options) => {
          if (!globalThis.astroAsset.staticImages) {
            globalThis.astroAsset.staticImages = /* @__PURE__ */ new Map();
          }
          let filePath;
          if (globalThis.astroAsset.staticImages.has(options)) {
            filePath = globalThis.astroAsset.staticImages.get(options);
          } else {
            if (!isESMImportedImage(options.src)) {
              return options.src;
            }
            filePath = prependForwardSlash(
              joinPaths(
                settings.config.base,
                settings.config.build.assets,
                propsToFilename(options)
              )
            );
            globalThis.astroAsset.staticImages.set(options, filePath);
          }
          return filePath;
        };
      },
      async buildEnd() {
        if (mode != "build") {
          return;
        }
        const dir = settings.config.output === "server" ? settings.config.build.server : settings.config.outDir;
        await copyWasmFiles(new URL("./chunks", dir));
      },
      async renderChunk(code) {
        const assetUrlRE = /__ASTRO_ASSET_IMAGE__([a-z\d]{8})__(?:_(.*?)__)?/g;
        let match;
        let s;
        while (match = assetUrlRE.exec(code)) {
          s = s || (s = new MagicString(code));
          const [full, hash, postfix = ""] = match;
          const file = this.getFileName(hash);
          const outputFilepath = normalizePath(resolvedConfig.base + file + postfix);
          s.overwrite(match.index, match.index + full.length, outputFilepath);
        }
        if (s) {
          return {
            code: s.toString(),
            map: resolvedConfig.build.sourcemap ? s.generateMap({ hires: true }) : null
          };
        } else {
          return null;
        }
      }
    },
    {
      name: "astro:assets:esm",
      enforce: "pre",
      configResolved(viteConfig) {
        resolvedConfig = viteConfig;
      },
      async load(id) {
        if (/\.(jpeg|jpg|png|tiff|webp|gif|svg)$/.test(id)) {
          const url = pathToFileURL(id);
          const meta = await imageMetadata(url);
          if (!meta) {
            return;
          }
          if (!this.meta.watchMode) {
            const pathname = decodeURI(url.pathname);
            const filename = path.basename(pathname, path.extname(pathname) + `.${meta.format}`);
            const handle = this.emitFile({
              name: filename,
              source: await fs.readFile(url),
              type: "asset"
            });
            meta.src = `__ASTRO_ASSET_IMAGE__${handle}__`;
          } else {
            url.searchParams.append("origWidth", meta.width.toString());
            url.searchParams.append("origHeight", meta.height.toString());
            url.searchParams.append("origFormat", meta.format);
            meta.src = rootRelativePath(settings.config, url);
          }
          return `export default ${JSON.stringify(meta)}`;
        }
      }
    }
  ];
}
export {
  assets as default
};
