// @bun
import {
  createDeployedAgentMapSnapshot,
  uploadDeployedAgentMapSnapshot
} from "./chunk-4wmnzrst.js";
import {
  createDeployedAgentManifest,
  tagDeployedAgentManifestBot,
  uploadDeployedAgentManifest
} from "./chunk-7krp2mgz.js";

// src/utils/component-uploader.ts
import { createHash } from "crypto";
import fs2 from "fs/promises";
import path from "path";

// src/utils/component-build-plugins.ts
import fs from "fs";
import crypto from "crypto";
function style(options = {}) {
  return {
    name: "style",
    setup({ onResolve, onLoad }) {
      onLoad({ filter: /\.css$/ }, async (args) => {
        const cssText = (await fs.promises.readFile(args.path, "utf8")).trimEnd();
        const cssFileId = crypto.createHash("md5").update(args.path).digest("hex");
        if (options.collect) {
          options.collect(cssText, cssFileId);
          return { contents: "", loader: "js" };
        }
        return {
          contents: `import { inject_style } from "__style_helper__"
inject_style(${JSON.stringify(cssText)}, "${cssFileId}")`,
          loader: "js"
        };
      });
      onResolve({ filter: /^__style_helper__$/ }, () => {
        return { path: "index.js", namespace: "style-helper" };
      });
      onLoad({ filter: /.*/, namespace: "style-helper" }, () => ({
        contents: `export function inject_style(text, id) {
` + `  if (typeof document === 'undefined') {
` + `    return
` + `  }
` + `  if (document.getElementById(id)) {
` + `    return
` + `  }
` + `  var style = document.createElement('style')
` + `  style.setAttribute("id", id)
` + `  var node = document.createTextNode(text)
` + `  style.appendChild(node)
` + `  document.head.appendChild(style)
` + `}`,
        loader: "js"
      }));
    }
  };
}
function globalReactPlugin() {
  return {
    name: "global-react-plugin",
    setup(build) {
      build.onResolve({ filter: /^react(\/jsx-runtime|\/jsx-dev-runtime)?$/ }, (args) => {
        return {
          path: args.path,
          namespace: "global-react-ns"
        };
      });
      build.onLoad({ filter: /.*/, namespace: "global-react-ns" }, (args) => {
        if (args.path === "react/jsx-runtime" || args.path === "react/jsx-dev-runtime") {
          return {
            contents: `const R = globalThis.React;
` + `function _jsx(type, props, key) {
` + `  if (props == null) return R.createElement(type, key !== undefined ? { key } : null);
` + `  const { children, ...rest } = props;
` + `  if (key !== undefined) rest.key = key;
` + `  return R.createElement(type, rest, children);
` + `}
` + `export const jsx = _jsx;
` + `export const jsxs = _jsx;
` + `export const jsxDEV = _jsx;
` + `export const Fragment = R.Fragment;`,
            loader: "js"
          };
        }
        return {
          contents: `export default globalThis.React; export const { useState, useEffect, useRef, useCallback, useMemo, useContext, createContext, createElement, Fragment, forwardRef, memo } = globalThis.React;`,
          loader: "js"
        };
      });
      build.onLoad({ filter: /\.(jsx?|tsx?)$/ }, async (args) => {
        let contents = await fs.promises.readFile(args.path, "utf8");
        contents = rewriteReactImports(contents);
        return {
          contents,
          loader: args.path.endsWith(".ts") || args.path.endsWith(".tsx") ? "tsx" : "jsx"
        };
      });
    }
  };
}
var reactImportPatterns = [
  [/import\s+React\s+from\s+['"]react['"];?/g, "const React = globalThis.React;"],
  [
    /import\s+\{\s*([^}]+)\s*\}\s+from\s+['"]react['"];?/g,
    (_, imports) => {
      const importsList = imports.split(",").map((imp) => imp.trim()).filter((imp) => !imp.startsWith("type "));
      return importsList.map((imp) => {
        const [name, alias] = imp.split(/\s+as\s+/).map((s) => s.trim());
        const varName = alias || name;
        return `const ${varName} = globalThis.React.${name};`;
      }).join(`
`);
    }
  ],
  [
    /import\s+React,\s*\{\s*([^}]+)\s*\}\s+from\s+['"]react['"];?/g,
    (_, imports) => {
      const importsList = imports.split(",").map((imp) => imp.trim()).filter((imp) => !imp.startsWith("type "));
      let result = `const React = globalThis.React;
`;
      result += importsList.map((imp) => {
        const [name, alias] = imp.split(/\s+as\s+/).map((s) => s.trim());
        const varName = alias || name;
        return `const ${varName} = globalThis.React.${name};`;
      }).join(`
`);
      return result;
    }
  ],
  [
    /import\s+\*\s+as\s+([A-Za-z0-9_$]+)\s+from\s+['"]react['"];?/g,
    (_, name) => {
      return `const ${name} = globalThis.React;`;
    }
  ]
];
function rewriteReactImports(text) {
  for (const [pattern, replacement] of reactImportPatterns) {
    if (typeof replacement === "string") {
      text = text.replace(pattern, () => replacement);
    } else {
      text = text.replace(pattern, replacement);
    }
  }
  return text;
}

// src/utils/component-uploader.ts
var componentTags = (name) => ({
  source: "integration",
  system: "true",
  integrationName: "webchat",
  feature: "custom-components",
  type: "component",
  name
});
async function deleteComponentFiles(client, names) {
  const staleFiles = [];
  for (const name of names) {
    let nextToken;
    do {
      const response = await client.listFiles({ tags: componentTags(name), nextToken });
      staleFiles.push(...response.files.map((f) => f.id));
      nextToken = response.meta.nextToken;
    } while (nextToken);
  }
  if (staleFiles.length > 0) {
    await Promise.allSettled(staleFiles.map((id) => client.deleteFile({ id })));
  }
  return staleFiles.length;
}
async function buildComponent(entryPoint) {
  const result = await Bun.build({
    entrypoints: [entryPoint],
    format: "esm",
    external: ["react", "react-dom"],
    plugins: [style({}), globalReactPlugin()]
  });
  if (!result.success) {
    const errors = result.logs.filter((l) => l.level === "error" || l.level === "warning").map((l) => l.message);
    if (!errors.length)
      errors.push("Build failed with no diagnostic output");
    return { success: false, code: null, errors };
  }
  const output = result.outputs[0];
  if (!output) {
    return { success: false, code: null, errors: ["Build produced no output"] };
  }
  const code = await output.text();
  return { success: true, code, errors: [] };
}
async function buildAndUploadComponents({
  agentRoot,
  project,
  client,
  log,
  only
}) {
  const components = only?.length ? project.customComponents.filter((c) => only.includes(c.definition.name)) : project.customComponents;
  const manifestPath = path.join(agentRoot, ".adk", "components.manifest.json");
  let manifest = {};
  try {
    manifest = JSON.parse(await fs2.readFile(manifestPath, "utf-8"));
  } catch {}
  const currentNames = new Set(project.customComponents.map((c) => c.definition.name));
  const removedNames = Object.keys(manifest).filter((name) => !currentNames.has(name));
  if (removedNames.length > 0) {
    log(`Cleaning up removed component(s): ${removedNames.join(", ")}`);
    await deleteComponentFiles(client, removedNames);
    for (const name of removedNames) {
      delete manifest[name];
    }
  }
  const groups = new Map;
  for (const comp of components) {
    const list = groups.get(comp.source) ?? [];
    list.push(comp);
    groups.set(comp.source, list);
  }
  for (const [source, group] of groups) {
    const allNames = group.map((c) => c.definition.name).join(", ");
    log(`Building ${allNames}...`);
    let bundleText;
    try {
      const { success, code, errors } = await buildComponent(source);
      if (!success || !code) {
        log(`\u26A0 Build failed for ${allNames}: ${errors.join("; ")}`);
        log(`\u26A0 Reverting to previous version if available.`);
        continue;
      }
      bundleText = code;
    } catch (error) {
      log(`\u26A0 Failed to build ${allNames}: ${error instanceof Error ? error.message : String(error)}`);
      continue;
    }
    const hash = createHash("sha256").update(bundleText).digest("hex");
    for (const comp of group) {
      const name = comp.definition.name;
      if (manifest[name]?.hash === hash) {
        log(`${name} unchanged, skipping upload`);
        continue;
      }
      try {
        log(`Uploading ${name}...`);
        const uploaded = await client.uploadFile({
          content: bundleText,
          key: `${name}.js`,
          accessPolicies: ["public_content"],
          publicContentImmediatelyAccessible: true,
          contentType: "application/javascript",
          tags: componentTags(name)
        });
        manifest[name] = {
          url: uploaded.file.url,
          deployedAt: new Date().toISOString(),
          hash
        };
        log(`\u2705 ${name} deployed`);
      } catch (error) {
        log(`\u26A0 Failed to upload ${name}: ${error instanceof Error ? error.message : String(error)}`);
      }
    }
  }
  await fs2.mkdir(path.dirname(manifestPath), { recursive: true });
  await fs2.writeFile(manifestPath, JSON.stringify(manifest, null, 2));
  log(`Saved ${Object.keys(manifest).length} component URL(s)`);
  return manifest;
}

// src/utils/prod-metadata-publisher.ts
async function publishProdMetadata(input) {
  const manifest = createDeployedAgentManifest(input.project, {});
  await uploadDeployedAgentManifest(input.client, manifest);
  await tagDeployedAgentManifestBot(input.client, input.botId);
  try {
    const agentMapSnapshot = createDeployedAgentMapSnapshot(input.project);
    await uploadDeployedAgentMapSnapshot(input.client, agentMapSnapshot);
    return {};
  } catch (error) {
    return {
      agentMapSnapshotWarning: error instanceof Error ? error.message : String(error)
    };
  }
}

export { style, globalReactPlugin, buildAndUploadComponents, publishProdMetadata };
