const passport = require("../../util/passport-config");
const jwt = require("jsonwebtoken");
const { emailValidator } = require("../../helpers/email-validator");
const Customers = require("../../models/Customers");

const axios = require("axios");
const { Op } = require("sequelize");

const { OAuth2Client } = require("google-auth-library");


const FB_APP_ID = "598331293126570";
const FB_APP_SECRET = "0cca88b6c5106b0e0eeee7c0ae74f88b";
const GOOGLE_CLIENT_ID = "581732651282-o44ff3gkacvarlt95fhvhc1ej1bt4lm4.apps.googleusercontent.com";

exports.accountRegisterV2 = async (req, res, next) => {
  const { email } = req.body;

  if (!email) return res.status(400).json({ success: false, message: "Email address is required." });

  const emailValidatorResponse = await emailValidator(email);
  const { isValidEmail, error } = emailValidatorResponse;

  if (error) return res.status(400).json(error);
  if (!isValidEmail)
    return res.status(400).json({ success: false, message: "Email address is either undeliverable/disposable." });

  passport.authenticate("signup_v2", { session: false }, (err, customer, info) => {
    if (err) {
      return next(err);
    }

    if (!customer) {
      return res.status(400).json({ success: false, message: info.message });
    }

    const token = jwt.sign({ customerId: customer.id, impersonation: false }, process.env.SECRETKEY, {
      expiresIn: "2h",
    });

    res.json({ success: true, token });
  })(req, res, next);
};

exports.accountDisable = async (req, res, next) => {
  try {
    const { customerId } = req;

    await Customers.update(
      {
        account_status: false,
      },
      {
        where: {
          id: customerId,
        },
      }
    );

    res.status(200).json({ success: true });
  } catch (err) {
    next(err);
  }
};

exports.accountRegisterFacebook = async (req, res, next) => {
  const { accessToken } = req.body;

  try {
    if (!accessToken) {
      return res.status(400).json({ error: "Access token is required." });
    }

    const tokenValidationUrl = `https://graph.facebook.com/debug_token?input_token=${accessToken}&access_token=${FB_APP_ID}|${FB_APP_SECRET}`;
    const tokenResponse = await axios.get(tokenValidationUrl);

    if (!tokenResponse.data || !tokenResponse.data.data.is_valid) {
      return res.status(401).json({ error: "Invalid Facebook access token." });
    }

    const userProfileUrl = `https://graph.facebook.com/me?fields=id,name,email,picture&access_token=${accessToken}`;
    const userProfileResponse = await axios.get(userProfileUrl);

    const user = userProfileResponse.data;

    if (!user) return res.status(401).json({ error: "Invalid Facebook user." });

    const { id, name, email } = user;
    const facebookUser = await Customers.findOne({
      where: {
        [Op.or]: [{ openauth_id: id }, { email }],
      },
    });

    if (facebookUser) return res.status(401).json({ error: "Facebook user is already registered or the email associated with the account is already registered." });

    const splittedName = name.split(" ");
    const createdFacebookUser = await Customers.create({
      first_name: splittedName[0],
      last_name: splittedName[1],
      email,
      openauth_id: id,
      password: "OPEN AUTH ACCOUNT",
      status: "Verified",
      account_source: "Facebook",
      verificationToken: "FACEBOOK",
      verificationTokenTimestamp: new Date(),
      longitude: 0,
      latitude: 0,
    });

    const token = jwt.sign({ customerId: createdFacebookUser.id, impersonation: false }, process.env.SECRETKEY, {
      expiresIn: "2h",
    });

    res.status(200).json({ success: true, token });
  } catch (err) {
    next(err);
  }
};

exports.accountLoginFacebook = async (req, res, next) => {
  const { accessToken } = req.body;

  try {
    if (!accessToken) {
      return res.status(400).json({ error: "Access token is required." });
    }

    const tokenValidationUrl = `https://graph.facebook.com/debug_token?input_token=${accessToken}&access_token=${FB_APP_ID}|${FB_APP_SECRET}`;
    const tokenResponse = await axios.get(tokenValidationUrl);

    if (!tokenResponse.data || !tokenResponse.data.data.is_valid) {
      return res.status(401).json({ error: "Invalid Facebook access token." });
    }

    const userProfileUrl = `https://graph.facebook.com/me?fields=id,name,email,picture&access_token=${accessToken}`;
    const userProfileResponse = await axios.get(userProfileUrl);

    const user = userProfileResponse.data;

    if (!user) return res.status(401).json({ error: "Invalid Facebook user." });

    const { id, name, email } = user;
    const facebookUser = await Customers.findOne({
      where: {
        openauth_id: id,
      },
    });

    if (!facebookUser) return res.status(401).json({ error: "Facebook user is not registered via Facebook Login." });

    const token = jwt.sign({ customerId: facebookUser.id, impersonation: false }, process.env.SECRETKEY, {
      expiresIn: "2h",
    });

    res.status(200).json({ success: true, token });
  } catch (err) {
    next(err);
  }
};

exports.accountRegisterGoogle = async (req, res, next) => {
  const { accessToken } = req.body;

  try {
    if (!accessToken) {
      return res.status(400).json({ error: "Access token is required." });
    }
    const client = new OAuth2Client(GOOGLE_CLIENT_ID);

    const ticket = await client.verifyIdToken({
      idToken: accessToken,
      audience: GOOGLE_CLIENT_ID,
    });

    const payload = ticket.getPayload();

    if (!payload) return res.status(401).json({ error: "Invalid Google user." });

    const { sub, given_name = "", family_name = "", email } = payload;

    const googleUser = await Customers.findOne({
      where: {
        [Op.or]: [{ openauth_id: sub }, { email }],
      },
    });

    if (googleUser) return res.status(200).json({ error: "Google user is already registered or the email associated with the account is already registered." });

    const createdGoogleUser = await Customers.create({
      first_name: given_name,
      last_name: family_name,
      email,
      openauth_id: sub,
      password: "OPEN AUTH ACCOUNT",
      status: "Verified",
      account_source: "Google",
      verificationToken: "GOOOGLE",
      verificationTokenTimestamp: new Date(),
      longitude: 0,
      latitude: 0,
    });

    const token = jwt.sign({ customerId: createdGoogleUser.id, impersonation: false }, process.env.SECRETKEY, {
      expiresIn: "2h",
    });

    res.status(200).json({ success: true, token });
  } catch (err) {
    next(err);
  }
}

exports.accountLoginGoogle = async (req, res, next) => {
  const { accessToken } = req.body;

  try {
    if (!accessToken) {
      return res.status(400).json({ error: "Access token is required." });
    }

    const client = new OAuth2Client(GOOGLE_CLIENT_ID);

    const ticket = await client.verifyIdToken({
      idToken: accessToken,
      audience: GOOGLE_CLIENT_ID,
    });

    const payload = ticket.getPayload();

    if (!payload) return res.status(401).json({ error: "Invalid Google user." });

    const { sub, given_name = "", family_name = "", email } = payload;
    
    const googleUser = await Customers.findOne({
      where: {
        openauth_id: sub,
      },
    });

    if (!googleUser) return res.status(200).json({ error: "Google user is not registered via Google Login." });

    const token = jwt.sign({ customerId: googleUser.id, impersonation: false }, process.env.SECRETKEY, {
      expiresIn: "2h",
    });

    res.status(200).json({ success: true, token });
  } catch (err) {
    next(err);
  }
}