import "dotenv/config";
import express from "express";
import { createServer } from "http";
import net from "net";
import { createExpressMiddleware } from "@trpc/server/adapters/express";

import { appRouter } from "../routers";
import { createContext } from "./context";
import { serveStatic, setupVite } from "./vite";
import { externalApiRouter } from "../external-api";
import { getAllProjects, getAllArticles } from "../db";

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();
  app.set("trust proxy", 1); // Trust first proxy
  const server = createServer(app);
  // Configure body parser with larger size limit for file uploads
  app.use(express.json({ limit: "50mb" }));
  app.use(express.urlencoded({ limit: "50mb", extended: true }));

  // Security Headers Middleware
  app.use((req, res, next) => {
    res.setHeader("X-XSS-Protection", "1; mode=block");
    res.setHeader("X-Content-Type-Options", "nosniff");
    res.setHeader("X-Frame-Options", "SAMEORIGIN");
    res.setHeader("Referrer-Policy", "strict-origin-when-cross-origin");

    if (process.env.NODE_ENV === "production") {
      res.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
    }

    // Content Security Policy
    const scriptSrc = ["'self'", "'unsafe-inline'"];
    if (process.env.NODE_ENV === "development") {
      scriptSrc.push("'unsafe-eval'");
    }

    const csp = `
        default-src 'self'; 
        script-src ${scriptSrc.join(" ")}; 
        style-src 'self' 'unsafe-inline'; 
        img-src 'self' data: https: blob:; 
        font-src 'self' data:; 
        connect-src 'self' https: ws: wss:;
    `.replace(/\s{2,}/g, " ").trim();

    res.setHeader("Content-Security-Policy", csp);
    next();
  });

  // Global Rate Limiter for API
  app.use("/api", async (req, res, next) => {
    try {
      // Dynamic import to avoid circular dependencies if any, or just import at top if cleaner
      const { checkRateLimit } = await import("./security");
      // Limit: 300 requests per minute per IP
      checkRateLimit(req.ip || "unknown", 300, 60 * 1000);
      next();
    } catch (error: any) {
      if (error?.code === "TOO_MANY_REQUESTS") {
        res.status(429).json({ error: "Trop de requêtes. Veuillez réessayer plus tard." });
      } else {
        next(error);
      }
    }
  });

  // OAuth callback under /api/oauth/callback

  // tRPC API
  app.use(
    "/api/trpc",
    createExpressMiddleware({
      router: appRouter,
      createContext,
    })
  );

  // External REST API
  app.use("/api/external", externalApiRouter);

  // File Upload API (Protected)
  // Dynamic import to avoid circular dependency issues if any
  const { uploadRouter } = await import("../routers/upload");
  app.use("/api/media", uploadRouter);

  // Sitemap
  app.get("/sitemap.xml", async (req, res) => {
    try {
      const baseUrl = "https://leifo.fr";
      const [projects, articles] = await Promise.all([
        getAllProjects(true),
        getAllArticles(true)
      ]);

      const staticPages = [
        "",
        "/a-propos",
        "/services",
        "/services/sites-vitrine",
        "/services/e-commerce",
        "/services/web-app",
        "/portfolio",
        "/blog",
        "/contact",
        "/mentions-legales",
        "/politique-confidentialite",
        "/cgu"
      ];

      const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  ${staticPages
          .map((url) => `
  <url>
    <loc>${baseUrl}${url}</loc>
    <changefreq>monthly</changefreq>
    <priority>${url === "" ? "1.0" : "0.8"}</priority>
  </url>`)
          .join("")}
  ${projects
          .map((project) => `
  <url>
    <loc>${baseUrl}/portfolio/${project.slug}</loc>
    <lastmod>${project.completionDate ? new Date(project.completionDate).toISOString() : new Date().toISOString()}</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.7</priority>
  </url>`)
          .join("")}
  ${articles
          .map((article) => `
  <url>
    <loc>${baseUrl}/blog/${article.slug}</loc>
    <lastmod>${article.publishedAt ? new Date(article.publishedAt).toISOString() : new Date().toISOString()}</lastmod>
    <changefreq>weekly</changefreq>
    <priority>0.7</priority>
  </url>`)
          .join("")}
</urlset>`;

      res.header("Content-Type", "application/xml");
      res.send(sitemap);
    } catch (error) {
      console.error("Sitemap generation error:", error);
      res.status(500).send("Error generating sitemap");
    }
  });

  // Serve uploads folder statically
  const path = await import("path");
  app.use("/uploads", express.static(path.resolve("uploads")));

  // development mode uses Vite, production mode uses static files
  if (process.env.NODE_ENV === "development") {
    await setupVite(app, server);
  } else {
    serveStatic(app);
  }

  const preferredPort = parseInt(process.env.PORT || "3000");
  const port = await findAvailablePort(preferredPort);

  if (port !== preferredPort) {
    console.log(`Port ${preferredPort} is busy, using port ${port} instead`);
  }

  server.listen(port, () => {
    console.log(`Server running on http://localhost:${port}/`);
  });
}

startServer().catch(console.error);
