import express from "express";
import mongoose from "mongoose";
import cors from "cors";
import dotenv from "dotenv";
import multer from "multer";
import helmet from "helmet";
import morgan from "morgan";
import path from "path";
import { fileURLToPath } from "url";
import authRoutes from "./routes/auth.js";
import userRoutes from "./routes/users.js";
import postRoutes from "./routes/posts.js";
import { register } from "./controllers/auth.js";
import { createPost } from "./controllers/posts.js";
import { verifyToken } from "./middleware/auth.js";
import errorMiddleware from "./middleware/errorMiddleware.js";
import User from "./models/User.js";
import Post from "./models/Post.js";
import { users, posts } from "./data/index.js";

import File from "./models/File.js";
import cookieParser from "cookie-parser";

/* CONFIGURATIONS */
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
dotenv.config();
const app = express();

/* Use cookies for refreshtoken */
app.use(cookieParser()); // might not work when env.ENABLE_CORS == false

// CORS configuration
// if (process.env.ENABLE_CORS === "true") {
app.use(
  cors({
    origin: [
      process.env.CLIENT_URL,
      "http://localhost:3000",
      "http://localhost:8080",
      "http://127.0.0.1:3000",
      "http://localhost:5173",
      "http://127.0.0.1:5173",
    ],
    methods: ["GET", "POST", "PATCH", "DELETE", "OPTIONS"],
    allowedHeaders: ["Content-Type", "Authorization", "X-Requested-With"],
    credentials: true,
  }),
);
// }

app.use(
  express.json({
    limit: "30mb",
  }),
);
app.use(helmet());
// app.use(helmet.contentSecurityPolicy(false));
app.use(
  helmet.crossOriginResourcePolicy({
    policy: "cross-origin",
  }),
);
app.use(morgan("common"));

// Health check route for Kubernetes liveness probe
app.get("/", (req, res) => {
  res.status(200).send("OK");
});

/* FILE STORAGE */
// new with mongodb buffer
const upload = multer({
  storage: multer.memoryStorage(),
  limits: {
    fileSize: 15 * 1024 * 1024,
  }, // 15 MB, allow uploading the funny image :) would not make sense for a production website
});

/* ROUTES WITH FILES */
app.post("/auth/register", upload.single("picture"), register);
app.post("/posts", verifyToken, upload.single("picture"), createPost);

/* ROUTES */
app.use("/auth", authRoutes);
app.use("/users", userRoutes);
app.use("/posts", postRoutes);

/* MONGOOSE SETUP */
// mongodb start ---------------------------------

//  if dev:
mongoose.set("debug", true);

const PORT = process.env.PORT || 6001;

mongoose.connection.on("connected", () => {
  console.log("MongoDB connected");
});

mongoose.connection.on("error", (err) => {
  console.error("MongoDB error:", err);
});

mongoose.connection.on("disconnected", () => {
  console.log("MongoDB disconnected");
});

async function startServer() {
  try {
    await mongoose.connect(process.env.MONGO_URL, {
      serverSelectionTimeoutMS: 5000,
    });

    app.listen(PORT, () => {
      console.log(`Server running on port ${PORT}`);
    });
  } catch (err) {
    console.error("Initial MongoDB connection failed:", err);
    process.exit(1);
  }
}

startServer();
// mongodb end ---------------------------------

/* POST IMAGE ROUTE - post pictures stored as Buffer on the Post document */
/* Must be registered BEFORE /assets/:id to avoid the wildcard matching "posts" */
app.get("/assets/posts/:id", async (req, res) => {
  try {
    const post = await Post.findById(req.params.id).select("pictureData pictureContentType");

    if (!post || !post.pictureData) {
      return res.status(404).json({
        error: "No post image exists",
      });
    }

    res.set("Content-Type", post.pictureContentType || "application/octet-stream");
    res.send(post.pictureData);
  } catch (err) {
    if (err.name === "CastError") {
      return res.status(404).json({
        error: "Invalid post ID",
      });
    }
    res.status(500).json({
      error: err.message,
    });
  }
});

/* FILE RETRIEVAL ROUTE - user profile pictures from File collection */
app.get("/assets/:id", async (req, res) => {
  try {
    const file = await File.findById(req.params.id);

    if (!file) {
      return res.status(404).json({
        error: "No file exists",
      });
    }

    res.set("Content-Type", file.contentType);
    res.set("Content-Disposition", `inline; filename="${file.filename}"`);
    res.send(file.data);
  } catch (err) {
    // findById throws CastError if id is not a valid ObjectId
    if (err.name === "CastError") {
      return res.status(404).json({
        error: "Invalid file ID",
      });
    }
    res.status(500).json({
      error: err.message,
    });
  }
});

app.use(errorMiddleware);
