const path = require("path");
const Koa = require(path.join(__dirname, "../server/node_modules/koa"));
const koaStatic = require(path.join(__dirname, "../server/node_modules/koa-static"));
const { join } = require("path");
const mount = require(path.join(__dirname, "../server/node_modules/koa-mount"));

module.exports = ({ host, port, middleware, allowHost }) => {
  const assets = new Koa()
  assets.use(koaStatic(join(__dirname, "..", "client", "assets")));
  
  const app = new Koa();
  const validHosts = [];

  const isValidRequest = (request) => {
    if (validHosts.includes(request.hostname) !== true) {
      return false;
    }
    if (request.method !== "GET") {
      if (request.header.referer == null) {
        return false;
      }

      try {
        const refererUrl = new URL(request.header.referer);
        if (validHosts.includes(refererUrl.hostname) !== true) {
          return false;
        }

        if (refererUrl.pathname.startsWith("/blob/")) {
          return false;
        }
      } catch (e) {
        return false;
      }
    }

    return true;
  };

   app.on("error", (err, ctx) => {
    if (err && (err.code === 'ECONNRESET' || err.code === 'EPIPE')) {
      return;
    }
    console.error(err);
    if (ctx && isValidRequest(ctx.request)) {
      err.message = err.message || 'Internal server error';
      err.expose = true;
    }
    return null;
  });

  app.use(mount("/assets", assets));

  const maptiles = new Koa();
  maptiles.use(koaStatic(join(__dirname, "..", "maps", "tiles")));
  app.use(mount("/maptiles", maptiles));

  const mapcache = new Koa();
  mapcache.use(koaStatic(join(__dirname, "..", "maps", "cache")));
  app.use(mount("/mapcache", mapcache));


  const gamesStatic = new Koa();
  gamesStatic.use(koaStatic(join(__dirname, "..", "games")));
  app.use(mount("/game-assets", gamesStatic));

  app.use(mount("/js", koaStatic(path.join(__dirname, 'public/js'))));
  app.use(koaStatic(path.join(__dirname, 'public')));

  app.use(async (ctx, next) => {
  
    //console.log("Requesting:", ctx.path); // uncomment to check for HTTP requests
    
    const csp = [
      "default-src 'self'",
      "script-src 'self' http://localhost:3000/js",
      "style-src 'self'",
      "img-src 'self'",
      "media-src 'self' blob:",
      "worker-src 'self' blob:",
      "frame-src 'self'",
      "form-action 'self'",
      "object-src 'none'",
      "base-uri 'none'",
      "frame-ancestors 'none'"
    ].join("; ");

    ctx.set("Content-Security-Policy", csp);
    ctx.set("X-Frame-Options", "SAMEORIGIN");

    ctx.set("X-Content-Type-Options", "nosniff");

    ctx.set("Referrer-Policy", "same-origin");
    ctx.set("Permissions-Policy", "speaker=(self)");

    const validHostsString = validHosts.join(" or ");

    ctx.assert(
      isValidRequest(ctx.request),
      400,
      `Request must be addressed to ${validHostsString} and non-GET requests must contain non-blob referer.`
    );

    await next();
  });
  
  // pdf viewer
  const pdfjsPath = path.join(__dirname, '../server/node_modules/pdfjs-dist/build/pdf.min.js');
  app.use(koaStatic(pdfjsPath));

  middleware.forEach((m) => app.use(m));

  const server = app.listen({ host, port });

  server.on("listening", () => {
    const address = server.address();

    if (typeof address === "string") {
      throw new Error("HTTP server should never bind to Unix socket");
    }

    if (allowHost !== null) {
      validHosts.push(allowHost);
    }

    validHosts.push(address.address);

    if (validHosts.includes(host) === false) {
      validHosts.push(host);
    }
  });

  return server;
};

