import * as bcrypt from "bcrypt";
import { FastifyReply, FastifyRequest } from "fastify";
import { SALT_ROUNDS } from "../../utils/consts";
import prisma from "../../utils/prisma";
import {
  CodeSchema,
  EmailSchema,
  LoginSchema,
  PasswordResetSchema,
  SignupSchema,
} from "./schema";
import { $Enums } from "@prisma/client";
import { mail } from "../../utils/mail";

// ------------------------------------------------------------------------------------

export async function signUp(
  req: FastifyRequest<{
    Body: SignupSchema;
  }>,
  reply: FastifyReply
) {
  const data = req.body;

  const user = await prisma.user.findUnique({
    where: {
      email: data.email.toLowerCase(),
    },
  });

  if (user) {
    return reply.code(400).send({
      message: "Un utilisateur avec cette adresse mail existe déjà",
    });
  }

  const city = await prisma.city.findUnique({
    where: {
      id: data.cityId,
    },
  });

  if (!city) {
    return reply.code(400).send({
      message: "La ville n'existe pas",
    });
  }

  const position = await prisma.position.findUnique({
    where: {
      id: data.positionId,
    },
  });

  if (!position) {
    return reply.code(400).send({
      message: "La fonction n'existe pas",
    });
  }

  try {
    const hash = await bcrypt.hash(data.password, SALT_ROUNDS);
    await prisma.user.create({
      data: {
        civility: data.civility,
        firstName: data.firstName,
        lastName: data.lastName,
        cityId: data.cityId,
        positionId: data.positionId,
        phoneNumber: data.phoneNumber,
        email: data.email.toLowerCase(),
        password: hash,

        bio: "",
      },
    });

    return reply.code(201).send({});
  } catch (e) {
    return reply.code(500).send(e);
  }
}

// ------------------------------------------------------------------------------------

export async function login(
  req: FastifyRequest<{
    Body: LoginSchema;
  }>,
  reply: FastifyReply
) {
  const { email, password } = req.body;

  const user = await prisma.user.findUnique({
    where: { email: email },
    include: { company: true },
  });

  const isMatch = user && (await bcrypt.compare(password, user.password));

  if (!user || !isMatch || !user.active) {
    return reply.code(401).send({
      message: "Aucun compte actif trouvé avec ces informations",
    });
  }

  // if (user.company && !user.company.active) {
  //   return reply.code(401).send({
  //     message: "Votre entreprise a été desactivé par la CCIS",
  //   });
  // }

  // if (user.role === $Enums.Role.Admin) {
  //   return reply.code(401).send({
  //     message: "Vous êtes un admin",
  //   });
  // }

  const payload = {
    id: user.id,
    email: user.email,
    role: user.role,
  };

  const token = req.jwt.sign(payload, { expiresIn: "1d" });
  return reply.code(200).send({ access: token });
}

// ------------------------------------------------------------------------------------

export async function sendCode(
  req: FastifyRequest<{
    Body: EmailSchema;
  }>,
  reply: FastifyReply
) {
  const { email } = req.body;

  const user = await prisma.user.findUnique({
    where: { email: email },
    include: { company: true },
  });

  if (!user || !user.active) {
    return reply.code(401).send({
      message: "Aucun compte actif trouvé avec ces informations",
    });
  }

  if (user.company && !user.company.active) {
    return reply.code(401).send({
      message: "Votre entreprise a été desactivé par la CCIS",
    });
  }

  if (user.role === $Enums.Role.Admin) {
    return reply.code(401).send({
      message: "Vous êtes un admin",
    });
  }

  const code = Math.floor(100000 + Math.random() * 900000).toString();

  const mailOptions = {
    from: process.env.EMAIL_HOST_USER,
    to: user.email,
    subject: "Réinitialisation du mot de passe",
    html: `
    <p>Voici le code de pour la réinitialisation de mot de passe: ${code}</p>
    `,
  };

  try {
    await mail.sendMail(mailOptions);

    await prisma.user.update({
      where: { id: user.id },
      data: {
        resetPasswordCode: code,
        resetPasswordAt: new Date(),
      },
    });

    return reply.code(200).send({});
  } catch {
    return reply.code(400).send({});
  }
}

// ------------------------------------------------------------------------------------

export async function validateCode(
  req: FastifyRequest<{
    Body: CodeSchema;
  }>,
  reply: FastifyReply
) {
  const { email, code } = req.body;

  const user = await prisma.user.findUnique({
    where: { email: email },
    include: { company: true },
  });

  if (!user || !user.active) {
    return reply.code(401).send({
      message: "Aucun compte actif trouvé avec ces informations",
    });
  }

  if (user.company && !user.company.active) {
    return reply.code(401).send({
      message: "Votre entreprise a été desactivé par la CCIS",
    });
  }

  if (user.role === $Enums.Role.Admin) {
    return reply.code(401).send({
      message: "Vous êtes un admin",
    });
  }

  if (user.resetPasswordCode !== code) {
    return reply.code(400).send({
      message: "Le code est incorrect",
    });
  }
  if (!user.resetPasswordAt) {
    return reply.code(400).send({
      message: "Ce code a exipré, régénérer un nouveau",
    });
  }

  const time1 = new Date(user.resetPasswordAt).getTime();
  const time2 = new Date().getTime();

  const differenceInMilliseconds = Math.abs(time1 - time2);

  if (differenceInMilliseconds > 10 * 60 * 1000) {
    return reply.code(400).send({
      message: "Ce code a exipré, régénérer un nouveau",
    });
  }

  return reply.code(200).send({});
}

// ------------------------------------------------------------------------------------

export async function updatePassword(
  req: FastifyRequest<{
    Body: PasswordResetSchema;
  }>,
  reply: FastifyReply
) {
  const { email, code, password } = req.body;

  const user = await prisma.user.findUnique({
    where: { email: email },
    include: { company: true },
  });

  if (!user || !user.active) {
    return reply.code(401).send({
      message: "Aucun compte actif trouvé avec ces informations",
    });
  }

  if (user.company && !user.company.active) {
    return reply.code(401).send({
      message: "Votre entreprise a été desactivé par la CCIS",
    });
  }

  if (user.role === $Enums.Role.Admin) {
    return reply.code(401).send({
      message: "Vous êtes un admin",
    });
  }

  if (user.resetPasswordCode !== code) {
    return reply.code(400).send({
      message: "Le code est incorrect",
    });
  }
  if (!user.resetPasswordAt) {
    return reply.code(400).send({
      message: "Ce code a exipré, régénérer un nouveau",
    });
  }

  const time1 = new Date(user.resetPasswordAt).getTime();
  const time2 = new Date().getTime();

  const differenceInMilliseconds = Math.abs(time1 - time2);

  if (differenceInMilliseconds > 11 * 60 * 1000) {
    return reply.code(400).send({
      message: "Ce code a exipré, régénérer un nouveau",
    });
  }

  const hash = await bcrypt.hash(password, SALT_ROUNDS);

  await prisma.user.update({
    where: { id: user.id },
    data: {
      password: hash,
    },
  });

  return reply.code(200).send({});
}

// ------------------------------------------------------------------------------------
