import { loadEntry } from './loader';
import { defineModules } from './module';
import TaskCtrl from './task-ctrl';
import { runtime } from '../index';

export interface IOptions {
  preload?: { [filePath: string]: string };
  npmFilePrefix?: string; // https://cdn.jsdelivr.net/npm/, https://unpkg.com/
  npmFilePrefixByScope?: { [scope: string]: string };
  projFilePrefix?: string;
  defineFuncName?: string;
  extensions?: string[];
  sourceTransforms?: {};
  dependencies?: { [pkgName: string]: string };
  onDependencyMiss?: (pkgName: string, version: string) => void;
  onError?: (e) => void; // Syntax error
  onModuleError?: (e) => void;
  debug?: boolean;
  runtime?: Window;
  externals?: {
    [key: string]: string;
  };
}

const defaultOpts: IOptions = {
  npmFilePrefix: 'https://cdn.jsdelivr.net/npm/',
  npmFilePrefixByScope: {},
  projFilePrefix: '/',
  defineFuncName: 'define',
  extensions: ['.js', '.json'],
  onDependencyMiss: (pkgName, version) => {
    console.error(`The npm package ${pkgName}@${version} is not in the dependency list`);
  },
  debug: false,
  runtime,
  onModuleError: (e) => {
    console.error('lowcode module error ', e);
  },
  onError: (e) => {
    try {
      console.error('Error loading cmd modules', e);
    } catch (e) {}
  },
  externals: {},
};

export const taskCtrl = new TaskCtrl();

async function loadCmdModuleInteral(entries: string[], opts: IOptions = {}, taskId: number) {
  opts = { ...defaultOpts, ...opts };
  const loaded = await loadEntry(entries, opts, taskId);

  const result = {};
  if (!taskCtrl.isActive(taskId)) {
    return result;
  }
  const defined = defineModules(loaded, opts);
  entries.map((ent) => {
    try {
      result[ent] = defined[ent].execute();
    } catch (e) {
      opts.onModuleError(e);
    }
  });
  return result;
}

/**
 * Add Wrapper to be cancelable
 */
export function loadCmdModule(entries: string[], opts: IOptions = {}) {
  const taskId = taskCtrl.add();
  const promise = loadCmdModuleInteral(entries, opts, taskId);
  return {
    promise,
    cancel() {
      taskCtrl.cancel(taskId);
    },
  };
}

export function loadEsModule(entries: string[], opts: IOptions = {}) {
  const taskId = taskCtrl.add();
  const promise = loadCmdModuleInteral(entries, opts, taskId);
  return {
    promise,
    cancel() {
      taskCtrl.cancel(taskId);
    },
  };
}
