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: {
            [Op.or]: [{ email }, { phone: req.body.phoneNo }],
          },
        });

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

          if (existingCustomer.phone === req.body.phoneNo) {
            return done(null, false, {
              message: "Phone number is already registered.",
            });
          }
        }

        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,
          account_source: req.body.accountSource
            ? req.body.accountSource
            : null,
        });

        // 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;
