const { Op } = require("sequelize");
const envCredential = require("../../config");
const { error, success } = require("../../handlers");
const { User } = require("../../models");
const bcrypt = require("bcrypt");
var jwt = require("jsonwebtoken");
const {
  generateToken,
  getReqInformation,
  generateCode,
  generateOTP,
} = require("../../utils/Common");
const sendEmail = require("../../utils/SendEmail");
const genSalt = 10;
const SECRET_KEY = envCredential.SECRET_KEY;

const register = async (req, res) => {
  try {
    let payload = req.body;
    let user = await User.findOne({
      where: {
        email: payload?.email,
      },
    });
    if (user) {
      return error(res, {
        msg: "Email already registered. Please login",
      });
    }
    let checkUserName = await User.findOne({
      where: {
        userName: payload?.userName,
      },
    });
    if (checkUserName) {
      return error(res, {
        msg: "UserName already exists.",
      });
    }

    const hash = await bcrypt.hash(payload?.password, genSalt);
    payload["password"] = hash;

    user = await User.create(payload);
    const accessToken = await generateToken({ id: user.id, SECRET_KEY });
    delete user.dataValues.password;
    return success(res, {
      msg: "User created successfully!!",
      data: [{ user, accessToken }],
    });
  } catch (err) {
    return error(res, {
      msg: "Something went wrong!!",
      error: [err.message],
    });
  }
};

const updateDetail = async (req, res) => {
  try {
    let payload = req.body;
    let user = await User.findOne({
      where: {
        mobileNo: payload?.mobileNo,
      },
    });
    if (!user) {
      return error(res, {
        msg: "Email already registered. Please login",
      });
    }
    payload["username"] = payload.mobileNo;

    const hash = await bcrypt.hash(payload?.password, genSalt);
    payload["password"] = hash;

    await User.update(payload, {
      where: {
        mobileNo: payload.mobileNo,
      },
    });
    const accessToken = await generateToken({ id: user.id, SECRET_KEY });
    delete user.dataValues.password;
    return success(res, {
      msg: "User registered successfully!!",
      data: [{ user, accessToken }],
    });
  } catch (err) {
    return error(res, {
      msg: "Something went wrong!!",
      error: [err.message],
    });
  }
};

const login = async (req, res) => {
  try {
    let payload = req.body;
    let userTypeArr = ["user", "agent"];
    if (payload?.loginType == "agent") {
      userTypeArr = ["agent"];
    }
    let user = await User.findOne({
      where: {
        [Op.or]: [
          {
            email: payload?.userName,
          },
          {
            userName: payload?.userName,
          },
        ],
        userType: {
          [Op.in]: userTypeArr,
        },
      },
      raw: true,
    });
    if (!user) {
      return error(res, {
        msg: "Please enter valid credential.",
      });
    }
    const isPasswordValid = await bcrypt.compare(
      payload?.password,
      user.password
    );
    if (!isPasswordValid) {
      return error(res, {
        msg: "Please enter valid credential.",
      });
    }
    if (payload?.notificationToken) {
      await User.update(
        {
          notificationToken: payload.notificationToken,
        },
        {
          where: {
            id: user.id,
          },
        }
      );
    }
    const accessToken = await generateToken({ id: user.id, SECRET_KEY });
    delete user.password;
    return success(res, {
      msg: "User logged in successfully",
      data: [{ user, accessToken }],
    });
  } catch (err) {
    return error(res, {
      msg: "Something went wrong!!",
      error: [err.message],
    });
  }
};

const checkUserName = async (req, res) => {
  try {
    let userName = req.params.userName;
    let user = await User.findOne({
      where: {
        userName: userName,
      },
    });

    if (user) {
      return success(res, {
        msg: "Username already exists",
        data: [{ isUserExists: true }],
      });
    }
    return success(res, {
      msg: "Username doesn't exists",
      data: [{ isUserExists: false }],
    });
  } catch (err) {
    return error(res, {
      msg: "Something went wrong!!",
      error: [err.message],
    });
  }
};

const forgetPasswordProcess = async (req, res) => {
  try {
    let payload = req.body;
    let user = await User.findOne({
      email: payload?.email,
    });
    const { baseUrl } = getReqInformation(req);
    console.log(user, "=-=-=user=-=-=-=");
    if (!user) {
      return error(res, {
        msg: "User with this email doesn't exists!!",
      });
    }
    let code = generateCode();
    user.verificationCode = code;
    await user.save();
    let data = {
      to: user.email,
      subject: "Forget Password",
      code: code,
      baseUrl,
    };
    console.log(data, "=-=-=-data-=-=-=");
    sendEmail("forget-password.handlebars", data);
    return success(res, {
      msg: "Email send successfully. Please check your email and change your password",
    });
  } catch (err) {
    console.log(err);
    return error(res, {
      msg: "Something went wrong!!",
    });
  }
};

const socialAuthentication = async (req, res) => {
  try {
    console.log("req.body", req.body);
    let payload = req.body;
    let names = payload?.name?.split(" ");
    let data = {
      userName: payload?.email,
      firstName: names.length > 0 ? names[0] : "",
      lastName: names.length > 1 ? names[1] : "",
      email: payload?.email,
      image: payload?.photo ?? "",
      isSocialSignup: true,
      socialType: "gmail",
      notificationToken: payload?.notificationToken ?? "",
    };

    let [user, created] = await User.findOrCreate({
      where: {
        email: payload?.email,
      },
      defaults: data,
    });
    console.log(user, "=-=-=", created);
    if (!user?.isSocialSignup) {
      return error(res, {
        msg: "Please login using email and password gmail login is not enabled for this account!!",
      });
    }
    if (payload?.notificationToken) {
      user.notificationToken = payload.notificationToken;
      await user.save();
    }
    const accessToken = await generateToken({ id: user.id, SECRET_KEY });
    delete user.password;
    return success(res, {
      msg: "User logged in successfully",
      data: [{ user, accessToken }],
    });
  } catch (err) {
    console.log(err);
    return error(res, {
      msg: "Something went wrong!!",
    });
  }
};

const sendOtp = async (req, res) => {
  try {
    let payload = req.body;
    let user = await User.findOne({
      where: {
        mobileNo: payload?.mobileNo,
      },
    });
    let otp = generateOTP();
    if(!user && payload.type == "agent"){
      return error(res,{
        msg: "Account doesn't exists. Please contact admin."
      })
    }
    if (user) {
      if(payload.type && user.userType != payload.type){
        return error(res,{
          msg: "Invalid phone no for "+ payload.type + " login."
        })
      }
      await User.update(
        {
          verificationCode: otp,
          countryCode: payload.countryCode
        },
        {
          where: {
            id: user.id,
          },
        }
      );
    } else {
      await User.create({
        mobileNo: payload?.mobileNo,
        userName: payload.mobileNo,
        verificationCode: otp,
        userType: payload.type ?? "user",
        countryCode: payload.countryCode
      });
    }
    return success(res, {
      msg: "OTP send successfully",
      data: [],
    });
  } catch (err) {
    console.log(err);
    return error(res, {
      msg: "Something went wrong!!",
    });
  }
};

const verifyOtp = async (req, res) => {
  try {
    let payload = req.body;
    let user = await User.findOne({
      where: {
        mobileNo: payload?.mobileNo,
      },
    });

    if (!user) {
      return error(res, {
        msg: "User doesn't exists",
      });
    }
    if (user.verificationCode != payload.otp) {
      return error(res, {
        msg: "Invalid OTP",
      });
    }
    const accessToken = await generateToken({ id: user.id, SECRET_KEY });
    user.password = null;

    return success(res, {
      msg: "OTP verified successfully",
      data: [{ user, accessToken }],
    });
  } catch (err) {
    console.log(err);
    return error(res, {
      msg: "Something went wrong!!",
    });
  }
};

const changePassword = async (req, res) => {
  try {
    let payload = req.body;
    let user = await User.findOne({
      where: {
        id: req.user.id,
      },
    });

    if (!user) {
      return error(res, {
        msg: "User doesn't exists",
      });
    }
    const isPasswordValid = await bcrypt.compare(
      payload?.password,
      user.password
    );
    if (!isPasswordValid) {
      return error(res, {
        msg: "Please enter valid old password.",
      });
    }

    const hash = await bcrypt.hash(payload?.newPassword, genSalt);
    payload["password"] = hash;

    await User.update(payload, {
      where: {
        id: user.id,
      },
    });

    return success(res, {
      msg: "Password changed successfully",
      data: [user],
    });
  } catch (err) {
    console.log(err);
    return error(res, {
      msg: "Something went wrong!!",
    });
  }
};

module.exports = {
  register,
  login,
  checkUserName,
  forgetPasswordProcess,
  socialAuthentication,
  sendOtp,
  verifyOtp,
  updateDetail,
  changePassword,
};
