import express from "express";
import { createProxyMiddleware } from "http-proxy-middleware";
import path from "path";
import { fileURLToPath } from "url";
import { spawn } from "child_process";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const PORT = 8080;
const ELEVENTY_PORT = 8081;
const WORKER_PORT = 8787;
const WORKER_ENTRY = "./workers/dynamic-pages/index.js";

const startProcess = (command, args, name) => {
  console.log(`Starting ${name}...`);
  const process = spawn(command, args, { stdio: "inherit" });

  process.on("error", (err) => {
    console.error(`${name} error: ${err.message}`);
    process.exit(1);
  });

  process.on("exit", (code) => {
    console.log(`${name} exited with code ${code}`);
    if (code !== 0) process.exit(code);
  });

  return process;
};

const startEleventy = () =>
  startProcess(
    "npx",
    ["eleventy", "--serve", "--port", ELEVENTY_PORT],
    "Eleventy"
  );
const startWorker = () =>
  startProcess(
    "npx",
    ["wrangler", "dev", WORKER_ENTRY, "--port", WORKER_PORT],
    "Wrangler Worker"
  );

const app = express();

const setContentType = (req, res) => {
  const contentTypeMap = {
    ".css": "text/css",
    ".js": "application/javascript",
    ".json": "application/json",
    "/api/": "application/json",
    "/feeds/all": "application/xml",
    "/feeds/books": "application/xml",
    "/feeds/links": "application/xml",
    "/feeds/movies": "application/xml",
    "/feeds/posts": "application/xml",
    "/feeds/syndication": "application/xml",
  };

  for (const [key, value] of Object.entries(contentTypeMap)) {
    if (req.path.endsWith(key) || req.path.startsWith(key)) {
      res.setHeader("Content-Type", value);
      break;
    }
  }
};

app.use((req, res, next) => {
  setContentType(req, res);
  next();
});

app.use(
  express.static(path.join(__dirname, "dist"), { extensions: ["html"] })
);

const proxy = createProxyMiddleware({
  target: `http://localhost:${WORKER_PORT}`,
  changeOrigin: true,
  ws: true,
  pathRewrite: (path, req) => req.originalUrl,
  onError: (err, req, res) => {
    console.error(`Proxy error: ${err.message}`);
    res.status(504).send("Worker timeout or unreachable");
  },
});

app.use(
  [
    "/watching/movies",
    "/watching/shows",
    "/music/artists",
    "/music/genres",
    "/books",
  ],
  proxy
);

app.use((req, res) => {
  res.status(404).sendFile(path.join(__dirname, "dist", "404.html"), (err) => {
    if (err) res.status(404).send("Page not found");
  });
});

const startServer = () => {
  const server = app.listen(PORT, () => {
    console.log(`Server running at http://localhost:${PORT}`);
  });

  const shutdown = () => {
    console.log("Shutting down...");
    server.close(() => {
      console.log("Express server closed");
      process.exit(0);
    });
  };

  process.on("SIGINT", shutdown);
  process.on("SIGTERM", shutdown);
};

const initialize = async () => {
  try {
    startEleventy();
    startWorker();
    startServer();
  } catch (err) {
    console.error(`Initialization error: ${err.message}`);
    process.exit(1);
  }
};

initialize();