const db = require("../../db");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const nodemailer = require("nodemailer");
const { JWT_SECRET, JWT_EXPIRE } = require("../../config");

// Improved token generator
const generateToken = (user) => {
  return jwt.sign(
    {
      id: user.id,
      email: user.email,
      user_type: user.user_type,
    },
    JWT_SECRET,
    { expiresIn: JWT_EXPIRE }
  );
};

exports.register = async (req, res) => {
  try {
    const {
      first_name,
      last_name,
      email,
      mobile,
      is_indian = true,
      password,
      user_type,
      desired_course,
      current_city,
      district,
      referral_source,
    } = req.body;

    // Check if user already exists
    const existingUser = await db.User.findOne({
      where: {
        [db.Sequelize.Op.or]: [{ email }, { mobile }],
      },
    });

    if (existingUser) {
      return res.status(400).json({
        success: false,
        error: "User with this email or mobile already exists",
      });
    }

    // Hash password
    const salt = await bcrypt.genSalt(10);
    const hashedPassword = await bcrypt.hash(password, salt);

    // Create user
    const user = await db.User.create({
      first_name,
      last_name,
      email,
      mobile,
      is_indian,
      password: hashedPassword,
      user_type,
      desired_course,
      current_city,
      district,
      referral_source,
    });

    // Generate token
    const token = generateToken(user);

    res.status(201).json({
      success: true,
      message: "User registered successfully",
      token,
      data: {
        id: user.id,
        first_name: user.first_name,
        last_name: user.last_name,
        email: user.email,
        user_type: user.user_type,
      },
    });
  } catch (err) {
    console.error("Error:", err);
    res.status(500).json({
      success: false,
      error: "Registration failed",
    });
  }
};

exports.login = async (req, res) => {
  try {
    const { email, password } = req.body;

    // Check if user exists
    const user = await db.User.findOne({
      where: { email },
    });

    if (!user) {
      return res.status(401).json({
        success: false,
        error: "Invalid credentials",
      });
    }

    // Check password
    const isMatch = await bcrypt.compare(password, user.password);
    if (!isMatch) {
      return res.status(401).json({
        success: false,
        error: "Invalid credentials",
      });
    }

    // Update last login
    await user.update({ last_login: new Date() });

    // Generate token
    const token = generateToken(user);

    res.json({
      success: true,
      message: "Login successful",
      token,
      data: {
        id: user.id,
        first_name: user.first_name,
        last_name: user.last_name,
        email: user.email,
        user_type: user.user_type,
      },
    });
  } catch (err) {
    console.error("Error:", err);
    res.status(500).json({
      success: false,
      error: "Login failed",
    });
  }
};

// Email transporter configuration
const transporter = nodemailer.createTransport({
  service: "gmail",
  auth: {
    user: process.env.EMAIL_USER || "abhimanyu.digialgid@gmail.com",
    pass: process.env.EMAIL_PASS || "pfcu gesm vpgv xqae",
  },
  from: process.env.EMAIL_FROM || "vivekpatidar397@gmail.com",
});

const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";

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

    const user = await db.User.findOne({ where: { email } });

    if (!user) {
      return res.status(404).json({
        success: false,
        error: "User not found with this email",
      });
    }

    // Create JWT reset token (expires in 1 hour)
    const resetToken = jwt.sign(
      { id: user.id, action: "password_reset" },
      JWT_SECRET,
      { expiresIn: "1h" }
    );

    // URL encode the token for safety
    const encodedToken = encodeURIComponent(resetToken);
    const resetURL = `${frontendUrl}/reset-password/${encodedToken}`;

    await transporter.sendMail({
      to: user.email,
      subject: "Password Reset",
      html: `
        <p>You requested a password reset</p>
        <p>Click this link to set a new password:</p>
        <a href="${resetURL}">Reset Password</a>
        <p>This link will expire in 1 hour.</p>
        <p>If you didn't request this, please ignore this email.</p>
      `,
    });

    res.json({
      success: true,
      message: "Reset link sent to email",
    });
  } catch (err) {
    console.error("Error:", err);
    res.status(500).json({
      success: false,
      error: "Failed to send reset email",
    });
  }
};

exports.resetPassword = async (req, res) => {
  try {
    const { token } = req.params;
    const { password, confirmPassword } = req.body;

    // Verify passwords match
    if (password !== confirmPassword) {
      return res.status(400).json({
        success: false,
        error: "Passwords do not match",
      });
    }

    // URL decode the token first
    const decodedToken = decodeURIComponent(token);

    // Verify the JWT token
    const decoded = jwt.verify(decodedToken, JWT_SECRET);

    // Check if token is for password reset
    if (decoded.action !== "password_reset") {
      return res.status(400).json({
        success: false,
        error: "Invalid token",
      });
    }

    // Find user by ID from token
    const user = await db.User.findByPk(decoded.id);
    if (!user) {
      return res.status(404).json({
        success: false,
        error: "User not found",
      });
    }

    // Hash new password
    const salt = await bcrypt.genSalt(10);
    const hashedPassword = await bcrypt.hash(password, salt);

    // Update password and clear any existing reset tokens
    await user.update({
      password: hashedPassword,
      resetToken: null,
      expireToken: null,
    });

    res.json({
      success: true,
      message: "Password reset successfully",
    });
  } catch (err) {
    console.error("Error:", err);

    let errorMessage = "Invalid or expired token";
    if (err.name === "JsonWebTokenError") {
      errorMessage = "Invalid token format";
    } else if (err.name === "TokenExpiredError") {
      errorMessage = "Token has expired. Please request a new reset link.";
    }

    res.status(400).json({
      success: false,
      error: errorMessage,
    });
  }
};

exports.getMe = async (req, res) => {
  try {
    const user = await db.User.findByPk(req.user.id, {
      attributes: { exclude: ["password"] },
    });

    if (!user) {
      return res.status(404).json({
        success: false,
        error: "User not found",
      });
    }

    res.json({
      success: true,
      data: user,
    });
  } catch (err) {
    console.error("Error:", err);
    res.status(500).json({
      success: false,
      error: "Failed to fetch user data",
    });
  }
};
