var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);

// src/fn.ts
var fn_exports = {};
__export(fn_exports, {
  Fn: () => Fn
});
module.exports = __toCommonJS(fn_exports);
var import_debug3 = __toESM(require("debug"));

// src/plugin.ts
var import_debug2 = __toESM(require("debug"));
var import_koa = __toESM(require("koa"));
var import_koa_compose = __toESM(require("koa-compose"));

// src/utils.ts
var import_debug = __toESM(require("debug"));
var debugLog = (0, import_debug.default)("@tomrpc/core");
var isArrowFunction = (func) => {
  if (typeof func === "function") {
    const source = func.toString();
    return /^\([^)]*\)\s*=>/.test(source);
  } else {
    return false;
  }
};
function getHttpMethods() {
  return [
    "get",
    "post",
    "put",
    "head",
    "delete",
    "options",
    "trace",
    "copy",
    "lock",
    "mkcol",
    "move",
    "purge",
    "propfind",
    "proppatch",
    "unlock",
    "report",
    "mkactivity",
    "checkout",
    "merge",
    "m-search",
    "notify",
    "subscribe",
    "unsubscribe",
    "patch",
    "search",
    "connect"
  ];
}
function isObject(item) {
  return item && typeof item === "object" && !Array.isArray(item);
}
function mergeDeep(target, ...sources) {
  if (!sources.length)
    return target;
  const source = sources.shift();
  if (isObject(target) && isObject(source)) {
    for (const key in source) {
      if (isObject(source[key])) {
        if (!target[key])
          Object.assign(target, { [key]: {} });
        mergeDeep(target[key], source[key]);
      } else {
        Object.assign(target, { [key]: source[key] });
      }
    }
  }
  return mergeDeep(target, ...sources);
}

// src/plugin.ts
var log = (0, import_debug2.default)("@tomrpc/core/plugin");
var Plugable = class {
  constructor(cfg) {
    this.init = [];
    this.load = [];
    this.config = mergeDeep(
      {
        bind: {}
      },
      cfg
    );
    this.name = "base";
    this.app = new import_koa.default();
    this.init = [];
    this.load = [];
    this.prefix = this.config.prefix ? this.config.prefix : "";
    this.compose = import_koa_compose.default;
    this.load.push(this.getMiddleware());
  }
  /**
   * move middleware to load stage, use template pattern & compose
   */
  getMiddleware() {
    log("getMiddleware");
    const pre = this.pre();
    const process = this.process();
    const post = this.post();
    return (0, import_koa_compose.default)([pre, process, post]);
  }
  pre() {
    return async (ctx, next) => {
      log("pre");
      await next();
      log("pre end");
    };
  }
  post() {
    return async (ctx, next) => {
      log("after");
      await next();
      log("after end");
    };
  }
  process() {
    return async (ctx, next) => {
      log("process default");
      await next();
      log("process default end");
    };
  }
  use(x) {
    this.app.use(x);
  }
  addInit(i) {
    this.init.push(i);
  }
  addLoad(i) {
    this.load.push(i);
  }
};

// src/fn.ts
var log2 = (0, import_debug3.default)("@tomrpc/core/fn");
var Fn = class extends Plugable {
  constructor(cfg) {
    super(
      mergeDeep(
        {
          prefix: "/api",
          functions: []
        },
        cfg
      )
    );
    this.name = "Fn";
    this.prefix = this.config.prefix;
    this.app.use(this.compose([this.before(), this.mount(), this.default()]));
  }
  fn(key, fn) {
    if (!this.config["functions"])
      this.config["functions"] = {};
    const pre = key.split("")[0] == "/" ? "" : "/";
    this.config["functions"][pre + key] = fn;
  }
  add(items) {
    for (const [name, fn] of Object.entries(items)) {
      if (isArrowFunction(fn)) {
        console.log(
          `this.rpcFunctions[${name}] is arrow function, please use ctx as param, not this`
        );
      }
      if (this.config["functions"][name]) {
        log2(`add ${name}: ${fn}`);
        console.log(`this.rpcFunctions[${name}] exisit`);
      }
      this.fn(name, fn);
    }
  }
  default() {
    return async (ctx, next) => {
      log2("default");
      ctx.body = "[fn plugin] no fn repsonse, please check your fn if exist";
      log2("default end");
    };
  }
  mount() {
    return async (ctx, next) => {
      log2(this);
      const routers = this.config["functions"];
      log2(routers);
      const path = ctx.path;
      log2("mountMiddleware" + ctx.path);
      const key = "/" + path.replace("/", "").split("/").join(".");
      if (!["POST", "PUT", "PATCH"].includes(ctx.method) && !ctx.query.$p) {
        console.log("not match $p param, no process");
        ctx.body = "not match $p param, no process";
      } else {
        const param = ctx.method === "POST" ? ctx.request.body : JSON.parse(ctx.query.$p);
        log2(key);
        log2(param);
        log2(routers[key]);
        if (routers[key]) {
          const args = [...param, ctx];
          console.dir(`call fn ${ctx.path}, with [${param}]`);
          const result = routers[key].apply(ctx, args);
          ctx.body = result;
        } else {
          const msg = JSON.stringify(ctx, null, 4);
          ctx.body = ` not match path ${ctx.path}  
 ctx = ${msg}`;
          await next();
        }
      }
    };
  }
  before() {
    return async (ctx, next) => {
      log2("before");
      const key = ctx.path.replace("/", "").split("/").join(".");
      const lastKey = key.split(".").pop();
      const httpMethods = getHttpMethods();
      const supportMethods = [];
      httpMethods.forEach(function(m) {
        if (lastKey.indexOf(m) != -1) {
          log2(m);
          supportMethods.push(m);
          return m;
        }
      });
      if (supportMethods.length === 0) {
        log2(ctx.path + ",\u6CA1\u6709\u5339\u914D\u5230\u5305\u542Bget/post\u7B49\u5F00\u5934\u7684\u51FD\u6570");
        await next();
      } else if (ctx.method.toLowerCase() === supportMethods[0]) {
        console.log("\u5339\u914D\u5230\u5305\u542Bget/post\u7B49\u65B9\u6CD5\u7684\u51FD\u6570");
        await next();
      } else {
        log2("\u5339\u914D\u5230\u5305\u542Bget/post\u7B49\u65B9\u6CD5\u7684\u51FD\u6570\uFF0C\u4F46method\u4E0D\u5BF9");
        ctx.body = "process fn:" + lastKey + " , you need send " + supportMethods[0] + " request from client";
      }
      log2("beforeOne end");
    };
  }
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  Fn
});
