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 AgentCustomer = require("../../models/AgentCustomer");

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, registrationAgent = null } = 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 },
    async (err, customer, info) => {
      if (err) {
        return next(err);
      }

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

      if (registrationAgent && registrationAgent !== "") {
        const currentCustomerPromise = Customers.findOne({
          where: {
            id: customer.id,
          },
        });
        const existingAgentPromise = Customers.findOne({
          where: {
            agent_code: registrationAgent,
            account_status: true,
          },
        });
        const [currentCustomer, existingAgent] = await Promise.all([
          currentCustomerPromise,
          existingAgentPromise,
        ]);

        if (existingAgent) {
          currentCustomer.registrationAgent = existingAgent.id;
          await currentCustomer.save();
          await AgentCustomer.create({
            agent: registrationAgent,
            customer: customer.id,
          });
        }
      }

      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);
  }
};
