import * as ESBuild from "https://deno.land/x/esbuild@v0.25.0/wasm.js";

/**
 * Resolves a module specifier against an import map
 * @param {string} specifier - The module specifier to resolve (bare specifier or absolute URL)
 * @param {Object} importMap - The import map object containing imports and scopes
 * @param {string} baseURL - The base URL for context (especially for scopes)
 * @returns {string} The resolved URL
 */
function resolveImportMap(specifier, importMap, baseURL) {

  // Check for prefix matches in the main imports
  const result = checkPrefixMatch(specifier, importMap.imports);
  if (result) {
    return result
  }

  // First check scopes that match the baseURL (scope applies based on baseURL, not specifier)
  if (importMap.scopes) {
    const scopeKeys = Object.keys(importMap.scopes).sort((a, b) => b.length - a.length);
    
    for (const scopeKey of scopeKeys) {
      // Convert scope key to absolute URL and check if baseURL starts with it
      const scopeURL = new URL(scopeKey, baseURL).href;
      
      if (baseURL.startsWith(scopeURL)) {
        const scopeImports = importMap.scopes[scopeKey];
        
        // Check for prefix match in the scope
        const result = checkPrefixMatch(specifier, scopeImports);
        if (result) {
          return result;
        }
      }
    }
  }
}

/**
 * Helper function to check for prefix matches
 * @param {string} specifier - The specifier to check
 * @param {Object} mappings - Object with prefix mappings
 * @returns {string|null} The resolved path or null if no match
 */
function checkPrefixMatch(specifier, mappings) {

  const check = mappings[specifier];
  if(check){ return check; }

  const prefixes = Object.keys(mappings)
    .filter(key => key.endsWith('/') && specifier.startsWith(key))
    .sort((a, b) => b.length - a.length);
  
  for (const prefix of prefixes) {
      const remainder = specifier.slice(prefix.length);
      return mappings[prefix] + remainder;
  }
  
  return null;
}

const resolvePlugin =(fullPathDir:string, importMap):ESBuild.Plugin=>({
  name: "resolve-plugin",
  setup(build) {


    build.onResolve( {/* `/`, `./`, and `../` */ filter:/^(\/|\.\/|\.\.\/).*/}, args=>{
      const resolveRoot = args.importer||fullPathDir;
      const url = new URL(args.path, resolveRoot).href;

      const out = { path:url, namespace:"FULLPATH" };
      console.log(`SLASHPATH=>FULLPATH RESOLVE`, {args, out}, "\n");
      return out;
    } );

    build.onResolve({filter:/.*/}, args=>{

      const check = resolveImportMap(args.path, importMap, args.importer||fullPathDir);
      console.log("pth??", check);
      if(check)
      {
        const resolveRoot = args.importer||fullPathDir;
        const out = { path:new URL(check, resolveRoot).href, namespace:"FULLPATH" };
        console.log(`IMPORTMAP RESOLVE`, {args, out}, "\n");
        return out;
      }

    })

    build.onLoad(
      {/* `file://`, `http://`, and `https://` */ filter:/^(file:\/\/|http:\/\/|https:\/\/).*/},
      async(args)=>
      {
        const contents = await fetch(args.path).then(r=>r.text());
        const out = { contents, loader: `tsx` };
        console.log(`FULLPATH LOAD`, {args, out:{...out, contents:contents.substring(0, 100)}}, "\n");
        return out;
      } );
  },
});

await ESBuild.initialize({ worker: false });
export type ImportMap = {imports?:Record<string, string>, scopes?:Record<string, Record<string, string>>}
export type BuildOptions = ESBuild.BuildOptions;

/**
 * 
 * @param {string} directory Full file:// or http(s):// path to the directory containing assets you want to build (needed to resolve relative imports)
 * @param {ESBuild.BuildOptions} [buildOptions={}] ESBuild "build" options (will be merged with "reasonable defaults") for docs: https://esbuild.github.io/api/#general-options
 * @param {ImportMap|null} [importMap={}] An object to act as the import map ({imports:Record<string, string>}). If this is left blank, a configuration will be scanned for in the "directory"
 * @returns {Promise<ESBuild.BuildResult<ESBuild.BuildOptions>>} build result
 */
export default async function Build(directory, buildOptions={}, importMap = {})
{
  console.log("using import map", importMap);
  const configuration:ESBuild.BuildOptions = {
    entryPoints: ["entry"],
    bundle: true,
    minify: true,
    format: "esm",
    jsx: "automatic",
    jsxImportSource: "react",
    ...buildOptions,
    plugins: [
      resolvePlugin(directory, importMap),
      ...buildOptions.plugins||[]
    ]
  };

  const result = await ESBuild.build(configuration);
  return result;
}
export { ESBuild };