import { NextApiRequest, NextApiResponse } from "next"
import logging, { Logging } from "../../lib/backend/logging"
import getPlayerByNameDB from "../../lib/backend/components/getPlayerByNameDB"
import checkPasswordIsValid from "../../lib/backend/components/checkPasswordIsValid"
import createTokenDB from "../../lib/backend/components/createTokenDB"
import sendResponse from "../../lib/backend/components/sendResponse"
import sendError from "../../lib/backend/components/sendError"
import { setCookie } from "cookies-next"
import { Player, Token } from "@prisma/client"
import prisma from "../../lib/prisma"

interface Data {
  loggedIn: boolean
}

export default async function login(
  req: NextApiRequest,
  res: NextApiResponse<any>
) {
  const { username, password } = req.body
  return preCheck({
    req,
    res,
    username,
    password,
    newTokenType: "REFRESH" as Token["type"],
  })
    .then(getPlayerByNameDB)
    .then(checkPasswordIsValid)
    .then(createTokenDB)
    .then(loginResponse<Data>)
    .then(sendResponse<Data>)
    .catch((err) => sendError(req, res, err))
}

async function preCheck<T>(
  payload: T & {
    req: NextApiRequest
    res: NextApiResponse<T>
  }
) {
  const { req } = payload
  const oldRefreshToken = req.cookies.token
  // Check for old cookie, if unused invalidate it
  const oldDBToken = await prisma.token.findUnique({
    where: {
      token: oldRefreshToken,
    },
  })
  if (oldDBToken?.used) {
    await prisma.token.update({
      where: {
        token: oldRefreshToken,
      },
      data: {
        used: true,
      },
    })
    await logging("Old token has been invalidated.", ["debug"], req)
  }
  return { ...payload, noCookiePresent: true }
}

async function loginResponse<T>(payload: {
  player: Player
  passwordIsValid: boolean
  refreshToken: string
  refreshTokenDB: Token
  req: NextApiRequest
  res: NextApiResponse<T>
}) {
  const { player, refreshToken, refreshTokenDB, req, res } = payload

  // Set login cookie
  setCookie("token", refreshToken, {
    req,
    res,
    maxAge: 172800000,
    httpOnly: true,
    sameSite: true,
    secure: true,
  })

  // Successfull response
  return {
    req,
    res,
    result: {
      message:
        "User " +
        player.id +
        " logged in and generated Refresh-Token: " +
        refreshTokenDB.id,
      body: { loggedIn: true },
      type: ["debug", "info.cyan"] as Logging[],
    },
  }
}
