import express from "express";
import multer, { FileFilterCallback } from "multer";
import sizeOf from "image-size";
import * as fsp from "fs/promises";
import * as path from "path";
import moment from "moment";
const app = express();
const publicDirname = path.join(__dirname, "../public");
const uploadDirname = path.join(__dirname, "../uploads");
const MAX_FILE_SIZE_IN_BYTES = 15 * 1_000_000; // 15 mb
const DEVELOPMENT_PORT = 8000;
const APP_SOCKET_PATH = "./app.sock";
const IMAGE_SQUARE_VALIDATION_TOLERENCE = 0.2;

import allowedUsers from "./allowedUsers.json";

import * as fs from "fs";
import * as dotenv from "dotenv";
import { validateForm } from "./handleForm";
import { completelyCreateEvent, createMarkdownFile } from "./eventCreator";
import { trainCase } from "case-anything";

dotenv.config();

const devQuestId = "cdalek";

const validateAuthorization = (req, res, next) => {
  const userId =
    process.env.NODE_ENV == "production"
      ? req.get("X-CSC-ADFS-Username")
      : devQuestId;

  if (!allowedUsers.includes(userId)) {
    res.status(401);
    res.sendFile(path.join(publicDirname, "unauthorized.html"));
  } else {
    return next();
  }
};

// Validate user's quest id
app.use(validateAuthorization);

// Configure multer for file uploads
const storage = multer.diskStorage({
  destination: function (req, file, callback) {
    callback(null, uploadDirname);
  },
  filename: function (req, file, callback) {
    callback(null, Date.now() + "--" + file.originalname);
  },
});

const fileFilter = async (
  _,
  file: Express.Multer.File,
  callback: FileFilterCallback
) => {
  let mimeType = file.mimetype.toLowerCase();
  if (
    !mimeType.includes("jpeg") &&
    !mimeType.includes("png") &&
    !mimeType.includes("jpg")
  ) {
    callback(
      Error("Invalid file type! Only JPEG and PNG files are supported!")
    );
  } else {
    callback(null, true);
  }
};

const validateImageIsSquare = async (file: Express.Multer.File) => {
  const dimensions = sizeOf(file.path);
  const ratio = dimensions.height / dimensions.width;

  return (
    ratio < 1 + IMAGE_SQUARE_VALIDATION_TOLERENCE &&
    ratio > 1 - IMAGE_SQUARE_VALIDATION_TOLERENCE
  );
};

let upload = multer({
  storage: storage,
  fileFilter: fileFilter,
  limits: { fileSize: MAX_FILE_SIZE_IN_BYTES },
});

// Routes
app.get("/", async (req, res) => {
  res.sendFile(path.join(publicDirname, "index.html"));
  // makePullRequest();
});

app.post("/event", upload.single("poster"), async (req, res) => {
  const { name, short, long, start, end, register, location, online } =
    req.body;

  let processedEventOrError = validateForm(
    name,
    short,
    long,
    start,
    end,
    register,
    location,
    online,
    req.file
  );

  // Check error
  if (typeof processedEventOrError === "string") {
    res.status(400);
    res.send(processedEventOrError);
    return;
  }

  if (!(await validateImageIsSquare(req.file))) {
    // Delete the file
    await fsp.unlink(req.file.path);
    return res
      .status(400)
      .send("The poster photo must be approximately square.");
  }

  // TODO: Move this to event creator (and change the image path to where the image will actually be in the repo)
  // createMarkdownFile(processedEventOrError, uploadDirname, req.file?.path);
  const DATE_FORMAT = "MMMM DD yyyy";
  const formatDate = (date: Date) => moment(date).format(DATE_FORMAT);
  const prTitle = `[EV] New Event: ${name} (${formatDate(new Date())})`;
  const prBody = `This PR has been autogenerated by Eventr. Please take a look at the details to see if its correct, and merge if it looks good.`;

  completelyCreateEvent(processedEventOrError, prTitle, prBody, req.file?.path);
  res.send("The event has been added successfully.");
});

function initUploadDir() {
  // Create upload directory if it doesn't exist already
  if (!fs.existsSync(uploadDirname)) {
    fs.mkdirSync(uploadDirname);
  }
}

//  Allows serving static files
app.use(express.static(publicDirname));
initUploadDir();

if (process.env.NODE_ENV === "production") {
  if (fs.existsSync(APP_SOCKET_PATH)) {
    fs.rmSync(APP_SOCKET_PATH);
  }
  app.listen(APP_SOCKET_PATH, () => {
    fs.chmodSync(APP_SOCKET_PATH, 0o777);
    console.log(`Listening on ${APP_SOCKET_PATH}`);
  });
} else {
  app.listen(DEVELOPMENT_PORT, () => {
    console.log(`Listening on http://localhost:${DEVELOPMENT_PORT}`);
  });
}
