import "dotenv/config";
import express from "express";
import { createServer } from "http";
import net from "net";
import path from "path";
import { fileURLToPath } from "url";
import { spawn } from "child_process";
import { request as httpRequest } from "http";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
import { createExpressMiddleware } from "@trpc/server/adapters/express";
import { setupOAuthRoutes } from "./oauth.ts";
import { registerEmailAuthRoutes } from "./emailAuth.ts";
// Stripe webhook removed - using Square only
import { registerSquarePaymentRoutes } from "./squareWebhook.ts";
import { registerGamesImportEndpoint } from "./gamesImportEndpoint.ts";
import { appRouter } from "../routers.ts";
import { createContext } from "./context.ts";
import { serveStatic, setupVite } from "./vite.ts";
import { createRateLimiter } from "../middleware/rateLimiter.ts";
import { csrfProtection } from "../middleware/csrfProtection.ts";
import { adminNotificationService } from "./wsNotifications.ts";
import { initializeSocketIO } from "./socketio-integration.ts";

function isPortAvailable(port: number): Promise<boolean> {
  return new Promise(resolve => {
    const server = net.createServer();
    server.listen(port, () => {
      server.close(() => resolve(true));
    });
    server.on("error", () => resolve(false));
  });
}

async function findAvailablePort(startPort: number = 3000): Promise<number> {
  for (let port = startPort; port < startPort + 20; port++) {
    if (await isPortAvailable(port)) {
      return port;
    }
  }
  throw new Error(`No available port found starting from ${startPort}`);
}

async function startServer() {
  const app = express();
  // Trust proxy to properly handle X-Forwarded-* headers
  app.set('trust proxy', 1);
  // Add www redirect middleware - redirect www.playplaycoinkrazy.com to playplaycoinkrazy.com
  app.use((req, res, next) => {
    const host = req.get("host") || "";
    if (host.startsWith("www.")) {
      const newHost = host.replace(/^www\./, "");
      const protocol = req.protocol || "https";
      return res.redirect(301, `${protocol}://${newHost}${req.originalUrl}`);
    }
    next();
  });

  const server = createServer(app);
  // Initialize WebSocket notification service
  adminNotificationService.initializeWebSocket(server);
  // Initialize Socket.io for real-time activity feed and revenue forecasting
  initializeSocketIO(server);
  // Stripe webhook removed - using Square only for payments
  // Configure body parser with larger size limit for file uploads
  app.use(express.json({ limit: "50mb" }));
  // Register rate limiting middleware for API routes only (disabled in development)
  if (process.env.NODE_ENV === "production") {
    const rateLimiter = createRateLimiter({ windowMs: 15 * 60 * 1000, maxRequests: 100 });
    app.use("/api", (req, res, next) => {
      // Skip rate limiting for tRPC endpoints
      if (req.path.startsWith("/trpc")) {
        return next();
      }
      rateLimiter(req, res, next);
    });
  }
  // Register CSRF protection middleware (exclude auth endpoints)
  app.use((req, res, next) => {
    // Skip CSRF for auth endpoints, tRPC (has its own auth), and OAuth callbacks
    if (
      req.path.startsWith("/api/auth/") ||
      req.path.startsWith("/api/trpc") ||
      req.path.startsWith("/api/oauth/") ||
      req.path.startsWith("/api/square") ||
      req.path === "/api/auth/create-admin"
    ) {
      return next();
    }
    csrfProtection(req, res, next);
  });
  // Register Square payment routes
  registerSquarePaymentRoutes(app);
  app.use(express.urlencoded({ limit: "50mb", extended: true }));
  // Email/password auth routes
  await registerEmailAuthRoutes(app);
  // OAuth callback under /api/oauth/callback
  setupOAuthRoutes(app);
  // Games import endpoint
  registerGamesImportEndpoint(app);
  // Start PG Soft game server as a child process
  // pgsoft-server lives outside the project directory to avoid deployment size limits
  const pgSoftServerPath = process.env.PGSOFT_SERVER_PATH || path.resolve(__dirname, "../../../pgsoft-server");
  const pgSoftPort = 3001;
  try {
    const fs = await import("fs");
    if (fs.existsSync(pgSoftServerPath)) {
      const pgSoftEnv: NodeJS.ProcessEnv = {
        ...process.env,
        PGSOFT_PORT: String(pgSoftPort),
        DB_NAME: "pgsoft",
        DB_SSL: "true",
        AMBIENTE: "PROD",
        API_SECRET: "coinkrazy_pgsoft_secret_2024",
      };
      // Extract DB credentials from DATABASE_URL
      const dbUrl = process.env.DATABASE_URL || "";
      const dbMatch = dbUrl.match(/mysql:\/\/([^:]+):([^@]+)@([^:]+):(\d+)\//);
      if (dbMatch) {
        pgSoftEnv.DB_USERNAME = dbMatch[1];
        pgSoftEnv.DB_PASSWORD = dbMatch[2];
        pgSoftEnv.DB_HOST = dbMatch[3];
        pgSoftEnv.DB_PORT = dbMatch[4];
      }
      const pgSoftProcess = spawn("node", ["dist/indexprod.js"], {
        cwd: pgSoftServerPath,
        env: pgSoftEnv,
        stdio: ["ignore", "pipe", "pipe"],
      });
      pgSoftProcess.stdout?.on("data", (d: Buffer) => console.log(`[PGSoft] ${d.toString().trim()}`));
      pgSoftProcess.stderr?.on("data", (d: Buffer) => console.error(`[PGSoft] ${d.toString().trim()}`));
      pgSoftProcess.on("error", (err: Error) => console.error(`[PGSoft] Spawn error: ${err.message}`));
      pgSoftProcess.on("exit", (code: number | null) => console.log(`[PGSoft] Server exited with code ${code}`));
      console.log(`[PGSoft] Game server starting on port ${pgSoftPort}...`);
    } else {
      console.log(`[PGSoft] Server directory not found at ${pgSoftServerPath}, skipping startup.`);
    }
  } catch (err) {
    console.error(`[PGSoft] Failed to start game server:`, err);
  }

  // Proxy /pgsoft/* requests to the PG Soft game server
  app.use("/pgsoft", (req, res) => {
    const target = `http://localhost:${pgSoftPort}${req.url}`;
    const proxyReq = httpRequest(target, {
      method: req.method,
      headers: { ...req.headers, host: `localhost:${pgSoftPort}` },
    }, (proxyRes) => {
      res.writeHead(proxyRes.statusCode || 200, {
        ...proxyRes.headers,
        "X-Frame-Options": "SAMEORIGIN",
        "Content-Security-Policy": "frame-ancestors 'self'",
      });
      proxyRes.pipe(res);
    });
    proxyReq.on("error", (err) => {
      console.error("[PGSoft Proxy] Error:", err.message);
      res.status(502).json({ error: "PG Soft server unavailable" });
    });
    if (req.body && Object.keys(req.body).length > 0) {
      const bodyStr = JSON.stringify(req.body);
      proxyReq.setHeader("Content-Length", Buffer.byteLength(bodyStr));
      proxyReq.write(bodyStr);
    }
    proxyReq.end();
  });

  // Serve HTML5 game files from static assets directory
  const gamesDir = path.resolve("/home/ubuntu/webdev-static-assets/games");
  app.use("/games", express.static(gamesDir, {
    setHeaders: (res) => {
      res.setHeader("X-Frame-Options", "SAMEORIGIN");
      res.setHeader("Cross-Origin-Embedder-Policy", "require-corp");
      res.setHeader("Cross-Origin-Opener-Policy", "same-origin");
    }
  }));
  // tRPC API
  app.use(
    "/api/trpc",
    createExpressMiddleware({
      router: appRouter,
      createContext,
    })
  );
  // development mode uses Vite, production mode uses static files
  if (process.env.NODE_ENV === "development") {
    await setupVite(app, server);
  } else {
    serveStatic(app);
  }

  // WebSocket server already initialized above

  const port = parseInt(process.env.PORT || "3000");
  
  server.listen(port, () => {
    console.log(`Server running on http://localhost:${port}/`);
    console.log(`WebSocket server initialized for admin notifications`);
  });
}

startServer().catch(console.error);
// Build cache buster: 1776115558
