import express from "express";
import { createServer } from "http";

import { createCorsMiddleware } from "../../utils/cors-config.js";
import { createCompressionMiddleware } from "../../utils/compression-config.js";
import cookieParser from "cookie-parser";
import { WebSocketServer } from "ws";

import { tunnelLogger } from "../../utils/logger.js";
import { AuthManager } from "../../utils/auth-manager.js";

import {
  describeC2SRelayError,
  extractRequestToken,
  sendC2SError,
} from "./c2s-relay-utils.js";
import {
  handleC2SRelayOpen,
  handleC2SRelayTest,
  type C2SOpenMessage,
} from "./c2s-relay.js";

import { registerTunnelRoutes } from "./routes.js";
import { initializeAutoStartTunnels } from "./manager.js";

const authManager = AuthManager.getInstance();

const app = express();
app.use(createCompressionMiddleware());
app.use(createCorsMiddleware(["GET", "POST", "PUT", "DELETE", "OPTIONS"]));
app.use(cookieParser());
app.use(express.json());
app.use((_req, res, next) => {
  res.setHeader("Cache-Control", "no-store");
  next();
});

registerTunnelRoutes(app);

const PORT = 30003;
const server = createServer(app);
const c2sRelayWss = new WebSocketServer({
  server,
  path: "/ssh/tunnel/c2s/stream",
});

c2sRelayWss.on("error", (error) => {
  tunnelLogger.error("C2S relay WebSocket server error", error, {
    operation: "c2s_relay_wss_error",
  });
});

c2sRelayWss.on("connection", (ws, req) => {
  let opened = false;

  ws.on("error", (error) => {
    tunnelLogger.error("C2S relay WebSocket connection error", error, {
      operation: "c2s_relay_ws_error",
    });
  });

  ws.once("message", async (raw) => {
    try {
      const token = extractRequestToken(req);
      const payload = token ? await authManager.verifyJWTToken(token) : null;
      if (!payload?.userId || payload.pendingTOTP) {
        sendC2SError(ws, "Authentication required");
        ws.close();
        return;
      }

      const message = JSON.parse(raw.toString()) as C2SOpenMessage;
      if (message.type !== "open" && message.type !== "test") {
        throw new Error("Invalid client tunnel relay request");
      }

      opened = true;
      if (message.type === "test") {
        await handleC2SRelayTest(ws, message, payload.userId);
      } else {
        await handleC2SRelayOpen(ws, message, payload.userId);
      }
    } catch (error) {
      const message = describeC2SRelayError(error);
      tunnelLogger.error("Failed to open C2S relay", error, {
        operation: "c2s_relay_open_failed",
      });
      sendC2SError(ws, message);
      ws.close();
    }
  });

  ws.on("close", () => {
    if (!opened) {
      tunnelLogger.info("C2S relay closed before opening", {
        operation: "c2s_relay_closed_before_open",
      });
    }
  });
});

server.listen(PORT, () => {
  setTimeout(() => {
    initializeAutoStartTunnels();
  }, 2000);
});
