const passport = require("passport");
const crypto = require("crypto"); // for generating token
const LocalStrategy = require("passport-local").Strategy;
const jwt = require("jsonwebtoken");
const Customers = require("../models/Customers"); // Adjust the path as needed
const bcryptjs = require("bcryptjs");
const nodemailer = require("nodemailer");
const { Op } = require("sequelize");
const AgentCustomer = require("../models/AgentCustomer");
const emailBuilder = require("../helpers/transporter");
// const { _verificationEmailRegister } = require("../helpers/email-templates/html-bodys");
const { verifyEmailTemplate } = require("../helpers/email-templates/html-bodys-new");
const { getCurrentDateTimeInGMT8 } = require("../helpers/common");

const generateToken = () => {
  // Generate a random 6-digit number
  return Math.floor(100000 + Math.random() * 900000).toString();
};

passport.use(
  "signup",
  new LocalStrategy({ usernameField: "email", passReqToCallback: true }, async (req, email, password, done) => {
    try {
      if (req.body.longitude === "" || req.body.latitude === "") {
        return done(null, false, { message: "Please pin your location" });
      }

      const existingCustomer = await Customers.findOne({ where: { email } });

      if (existingCustomer) {
        return done(null, false, {
          message: "Email address is already in use",
        });
      }

      // Adjust time to UTC+8:00
      const now = new Date(Date.now() + 8 * 60 * 60 * 1000);

      // Check if there's a pending token request within the last 5 minutes
      const fiveMinutesAgo = new Date(now - 5 * 60 * 1000);
      const recentTokenRequest = await Customers.findOne({
        where: {
          email,
          verificationTokenTimestamp: { [Op.gte]: fiveMinutesAgo },
        },
      });

      if (recentTokenRequest) {
        // If there's a recent token request, handle the case
        return done(null, false, {
          message: "Please wait before requesting a new token",
        });
      }

      let token = generateToken(); // generate token
      let tokenTimestamp = now;

      const created_timestamp = await getCurrentDateTimeInGMT8();

      const newCustomer = await Customers.create({
        type: req.body.type || "Buyer",
        buyer_type: req.body.buyerType || null,
        agent_code: req.body.agentCode || null,
        hardware_name: req.body.hardwareName || null,
        first_name: req.body.firstName,
        last_name: req.body.lastName,
        email: email,
        password: password,
        phone: req.body.phone || "",
        address: req.body.address,
        longitude: req.body.longitude,
        latitude: req.body.latitude,
        verificationToken: token,
        verificationTokenTimestamp: tokenTimestamp,
        status: "For Approval",
        created_timestamp: created_timestamp,
      });

      if (req.body.agentCode && req.body.agentCode.trim() !== "None") {
        await AgentCustomer.create({
          agent: req.body.agentCode,
          customer: newCustomer.id,
        });
      }

      // Send verification email
      await sendVerificationEmail(email, token);

      return done(null, newCustomer);
    } catch (error) {
      return done(error);
    }
  })
);

passport.use(
  "signup_v2",
  new LocalStrategy({ usernameField: "email", passReqToCallback: true }, async (req, email, password, done) => {
    try {
      const existingCustomer = await Customers.findOne({ where: { email } });

      if (existingCustomer) {
        return done(null, false, {
          message: "Email address is already in use",
        });
      }

      const now = new Date(Date.now() + 8 * 60 * 60 * 1000);

      const fiveMinutesAgo = new Date(now - 5 * 60 * 1000);
      const recentTokenRequest = await Customers.findOne({
        where: {
          email,
          verificationTokenTimestamp: { [Op.gte]: fiveMinutesAgo },
        },
      });

      if (recentTokenRequest) {
        return done(null, false, {
          message: "Please wait before requesting a new token",
        });
      }

      let token = generateToken();
      let tokenTimestamp = now;

      const created_timestamp = await getCurrentDateTimeInGMT8();

      const newCustomer = await Customers.create({
        type: "Buyer",
        first_name: req.body.firstName,
        last_name: req.body.lastName,
        email: email,
        password: password,
        phone: req.body.phoneNo || "",
        longitude: 0.0,
        latitude: 0.0,
        verificationToken: token,
        verificationTokenTimestamp: tokenTimestamp,
        // status: "For Approval",
        status: "Verified",
        created_timestamp: created_timestamp,
      });

      await sendVerificationEmail(`${req.body.firstName} ${req.body.lastName}`, email, token);

      return done(null, newCustomer);
    } catch (error) {
      return done(error);
    }
  })
);

async function sendVerificationEmail(user_name, email, token) {
  // Send the email
  try {
    const receivers = [email];
    const info = await emailBuilder(
      receivers,
      [],
      "Verify Your Email Address",
      true,
      verifyEmailTemplate(user_name, token),
      []
    );
    console.log("Email sent: " + info.response);
  } catch (error) {
    console.error("Error sending email:", error);
  }
}

passport.use(
  "login",
  new LocalStrategy({ usernameField: "email" }, async (email, password, done) => {
    try {
      const customer = await Customers.findOne({ where: { email } });

      if (!customer) {
        return done(null, false, { message: "Invalid email or password" });
      }

      if (customer.status !== "Verified") {
        return done(null, false, {
          message: "Please verify your account first",
        });
      }
      if (!customer.account_status) {
        return done(null, false, {
          message: "Account is disabled.",
        });
      }

      if (!(await customer.validatePassword(password))) {
        if (!(await customer._validatePasswordPhp(password))) {
          return done(null, false, { message: "Invalid email or password" });
        }
      }

      return done(null, customer);
    } catch (error) {
      return done(error);
    }
  })
);

passport.serializeUser((customer, done) => {
  done(null, customer.id);
});

passport.deserializeUser(async (id, done) => {
  try {
    const customer = await Customers.findByPk(id);
    done(null, customer);
  } catch (error) {
    done(error);
  }
});

module.exports = passport;
