import dotenv from "dotenv";

// Load environment variables
dotenv.config({ path: './.env' });

import express, { type Request, Response, NextFunction } from "express";
import session from "express-session";
import cors from "cors";
import { registerRoutes } from "./routes.js";
import { serveStatic } from "./static.js";
import { createServer } from "http";
import { setupWebSocket, websocket } from "./websocket.js";
import { attachOrgContext, requireOrgMember } from "./org-middleware.js";
import { getCorsOptions } from "./cors-config.js";

const app = express();
const httpServer = createServer(app);

// CORS configuration for all AeThex domains
app.use(cors(getCorsOptions()));

// Health check for Railway/monitoring
app.get("/health", (_req, res) => {
  res.json({ status: "healthy", timestamp: new Date().toISOString() });
});

// API status endpoint (moved from root to /api/status)
app.get("/api/status", (_req, res) => {
  const isKernel = process.env.OPS_Version ? true : false;
  
  res.json({
    status: isKernel ? "AeThex OS Unikernel: ONLINE" : "AeThex OS Simulation: ONLINE",
    mode: isKernel ? "KERNEL_NATIVE" : "HOSTED_SIMULATION",
    version: "1.0.0",
    endpoints: {
      link: "/api/os/link/*",
      entitlements: "/api/os/entitlements/*",
      subjects: "/api/os/subjects/*"
    }
  });
});

// Trust proxy for proper cookie handling behind Vite dev server
app.set("trust proxy", 1);

declare module "http" {
  interface IncomingMessage {
    rawBody: unknown;
  }
}

// Require session secret in production
const sessionSecret = process.env.SESSION_SECRET;
if (process.env.NODE_ENV === "production" && !sessionSecret) {
  throw new Error("SESSION_SECRET environment variable is required in production");
}

// Session configuration with security best practices
const isProduction = process.env.NODE_ENV === "production";

// For Unikernel local testing (localhost:8080), we must disable secure cookies
// because there is no SSL termination in the kernel itself yet.
// We detect if we are running in OPS/Nanos via the environment, or just assume
// that if we are "production" but not explicitly requiring HTTPS, we might be in a kernel.
// A safer check: if we are in OPS, process.env.OPS_Version might be present (if set),
// OR we can just relax this for now to fix the login loop.
const isSecure = isProduction && process.env.REQUIRE_HTTPS === "true";

app.use(
  session({
    secret: sessionSecret || "dev-only-secret-not-for-prod",
    resave: false,
    saveUninitialized: false,
    cookie: {
      secure: isSecure,
      httpOnly: true,
      sameSite: "lax",
      maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days
    },
    proxy: true, // Always trust proxy (Replit uses reverse proxy in both dev and prod)
  })
);


app.use(
  express.json({
    verify: (req, _res, buf) => {
      req.rawBody = buf;
    },
  }),
);

app.use(express.urlencoded({ extended: false }));

export function log(message: string, source = "express") {
  const formattedTime = new Date().toLocaleTimeString("en-US", {
    hour: "numeric",
    minute: "2-digit",
    second: "2-digit",
    hour12: true,
  });

  console.log(`${formattedTime} [${source}] ${message}`);
}

app.use((req, res, next) => {
  const start = Date.now();
  const path = req.path;
  let capturedJsonResponse: Record<string, any> | undefined = undefined;

  const originalResJson = res.json;
  res.json = function (bodyJson, ...args) {
    capturedJsonResponse = bodyJson;
    return originalResJson.apply(res, [bodyJson, ...args]);
  };

  res.on("finish", () => {
    const duration = Date.now() - start;
    if (path.startsWith("/api")) {
      let logLine = `${req.method} ${path} ${res.statusCode} in ${duration}ms`;
      if (capturedJsonResponse) {
        logLine += ` :: ${JSON.stringify(capturedJsonResponse)}`;
      }

      log(logLine);
    }
  });

  next();
});


(async () => {
  // Register routes (org middleware applied selectively within routes.ts)
  await registerRoutes(httpServer, app);

  // Setup WebSocket server for real-time notifications and Aegis alerts
  const io = setupWebSocket(httpServer);
  websocket.setIO(io);
  log("WebSocket server initialized", "websocket");

  app.use((err: any, _req: Request, res: Response, _next: NextFunction) => {
    const status = err.status || err.statusCode || 500;
    const message = err.message || "Internal Server Error";
    res.status(status).json({ message });
    throw err;
  });

  // importantly only setup vite in development and after
  // setting up all the other routes so the catch-all route
  // doesn't interfere with the other routes
  if (process.env.NODE_ENV === "production") {
    serveStatic(app);
  } else {
    const { setupVite } = await import("./vite");
    await setupVite(httpServer, app);
  }

  // ALWAYS serve the app on the port specified in the environment variable PORT
  // Other ports are firewalled. Default to 5000 if not specified.
  // this serves both the API and the client.
  // It is the only port that is not firewalled.
  const port = parseInt(process.env.PORT || "5000", 10);
  httpServer.listen(
    port,
    () => {
      log(`serving on port ${port}`);
      log(`WebSocket available at ws://localhost:${port}/socket.io`, "websocket");
    },
  );
})();
