import {
  Fn
} from "./chunk-RU73OROG.mjs";
import {
  log,
  mergeDeep
} from "./chunk-FKHYE7Y6.mjs";

// src/server.ts
import { bodyParser } from "@koa/bodyparser";
import Koa from "koa";
import compose2 from "koa-compose";
import mount from "koa-mount";

// src/index.ts
import compose from "koa-compose";
var combine = compose;
function createServer(cfg) {
  const rpc = new RpcServer(mergeDeep({ fn: {} }, cfg));
  const fn = new Fn(mergeDeep({}, cfg.fn));
  rpc.plugin(fn);
  return mergeDeep(rpc, {
    base: ".",
    init: rpc["config"]["hooks"]["init"],
    before: rpc["config"]["hooks"]["before"],
    load: rpc["config"]["hooks"]["load"],
    after: rpc["config"]["hooks"]["after"],
    dump: function() {
      console.dir("dump");
    },
    fn: function(key, fun) {
      fn.fn(key, fun);
    },
    add: function(items) {
      fn.add(items);
    }
  });
}

// src/server.ts
var LifeCycleConfig = {
  hooks: {
    init: [],
    // 后面需要改成Set，否则会出现重复问题
    before: [],
    load: [],
    after: [],
    default: async (ctx, next) => {
      log("default");
      ctx.body = "[core server] no middleware repsonse, please check your route";
      log("default end");
    }
  },
  before: async (server) => {
    const app = server.app;
    const loadMiddlewares = server.config.hooks.before;
    loadMiddlewares.forEach((mw) => {
      app.use(mw);
    });
  },
  init: async (server) => {
    log("init");
    const app = server.app;
    const loadMiddlewares = server.config.hooks.init;
    loadMiddlewares.forEach((mw) => {
      app.use(mw);
    });
  },
  load: async (server) => {
    const app = server.app;
    const loadMiddlewares = server.config.hooks.load;
    loadMiddlewares.forEach((mw) => {
      app.use(mw);
    });
  },
  after: async (server) => {
    const app = server.app;
    const loadMiddlewares = server.config.hooks.after;
    loadMiddlewares.forEach((mw) => {
      app.use(mw);
    });
  }
};
var RpcServer = class {
  /**
   * Usually, the Server accepts a strategy through the constructor, but also
   * provides a setter to change it at runtime.
   */
  constructor(cfg) {
    this.plugins = [];
    this.proxy = {
      init: [],
      load: [],
      before: {}
    };
    this.config = mergeDeep(LifeCycleConfig, cfg);
    this.app = new Koa();
    this.app.use(bodyParser());
    this.use = this.app.use;
  }
  /**
   * Usually, the Server allows replacing a Strategy object at runtime.
   */
  plugin(strategy) {
    this.plugins.push(strategy);
  }
  mount() {
    log("mount");
    const cfg = {};
    for (const plugin of this.plugins) {
      plugin.server = this;
      plugin.serverConfig = this.config;
      if (plugin.name === "base") {
        log("plugin name \u6CA1\u6709\u4FEE\u6539\uFF0C\u53EF\u80FD\u4F1A\u51FA\u73B0serverConfig\u83B7\u53D6\u95EE\u9898\uFF0C\u8BF7\u5173\u6CE8");
      }
      this.config[plugin.name] = plugin.config;
      cfg[plugin.name] = plugin;
    }
    for (const plugin of this.plugins) {
      if (plugin.config.proxy) {
        if (plugin.config.proxy.inject === "init") {
          log("plugin.config.proxy.inject init");
          this.proxy.init.push(plugin.proxy());
        }
        if (plugin.config.proxy.inject === "load") {
          log("plugin.config.proxy.inject load");
          this.proxy.load.push(plugin.proxy());
        }
        if (plugin.config.proxy.inject === "before") {
          log("plugin.config.proxy.inject before");
          for (const i in plugin.config.proxy.before) {
            const name = plugin.config.proxy.before[i];
            if (!this.proxy.before[name.toLowerCase()])
              this.proxy.before[name.toLowerCase()] = [];
            this.proxy.before[name.toLowerCase()].push(plugin.proxy());
          }
        }
      }
    }
    this.config.hooks.init = this.proxy.init;
    for (const plugin of this.plugins) {
      log("init stage");
      if (plugin.init.length > 0)
        this.config.hooks.init.push(...plugin.init);
    }
    this.config.init(this);
    this.config.hooks.load = this.proxy.load;
    for (const plugin of this.plugins) {
      log("load stage");
      if (plugin.load.length > 0)
        this.config.hooks.load.push(...plugin.load);
    }
    this.config.load(this);
    for (const plugin of this.plugins) {
      log("mount plugin " + plugin.prefix);
      const mw = this.proxy.before[plugin.name.toLowerCase()] || [];
      const app = plugin.prefix === "" ? mount(plugin.app) : mount(plugin.prefix, plugin.app);
      log(plugin.prefix);
      this.app.use(compose2([...mw, app]));
    }
    log("\u515C\u5E95\u7684else");
    this.app.use(this.config.hooks.default);
  }
  /**
   * make app ready, add before hook & mount & after hook
   */
  prepare() {
    this.config.before(this);
    this.mount();
    this.config.after(this);
    this.app.use(function(ctx) {
      ctx.body = "default";
    });
  }
  callback() {
    this.prepare();
    return this.app.callback();
  }
  /**
   * Start @tomrpc/core server with port
   */
  start(port) {
    this.prepare();
    const _port = port || 3e3;
    return this.app.listen(_port, (err) => {
      if (err) {
        console.error(err);
      } else {
        console.log("@tomrpc/core listening on " + _port);
      }
    });
  }
};

export {
  LifeCycleConfig,
  RpcServer,
  combine,
  createServer
};
