const nodemailer = require("nodemailer");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const crypto = require("crypto");
const { notifyUser, notifyManyUsers } = require("../services/notification.service");
const otpStore = {}; // Temporary in-memory store

const prisma = require("../lib/prisma");

//student register
exports.registerStudent = async (req, res) => {
  try {
    const {
      firstName,
      lastName,
      email,
      phone,
      fatherName,
      motherName,
      schoolName,
      fatherPhone,
      motherPhone,
    } = req.body;

    // Check if email exists
    const existingUser = await prisma.user.findUnique({ where: { email } });
    if (existingUser)
      return res.status(400).json({ message: "Email already exists" });

    // Create student (no password)
    const user = await prisma.user.create({
      data: {
        firstName,
        lastName,
        email,
        phone,
        fatherName,
        motherName,
        schoolName,
        fatherPhone,
        motherPhone,
        role: "student",
        status: "pending", // or "approved" if you want immediate access
      },
    });

    // Notify all admins and accountants
    const staff = await prisma.user.findMany({
      where: { role: { in: ["admin", "accountant"] } },
      select: { id: true },
    });

    const staffIds = staff.map((u) => u.id);
    
    if (staffIds.length > 0) {
      const message = `New student registered: "${user.firstName} ${user.lastName}" (Email: ${user.email}).`;
      await notifyManyUsers(req, staffIds, message, null); // system notification
    }

    return res.status(201).json({
      message: "Student registered successfully",
      user,
    });
  } catch (err) {
    console.error(err);
    return res.status(500).json({ message: "Server error" });
  }
};

// ----------------------
// Step 1: Send OTP
// ----------------------
exports.sendOtp = async (req, res) => {
  try {
    const { firstName, lastName, email, phone, password, role } = req.body;

    // Check if user already exists
    const existingUser = await prisma.user.findUnique({ where: { email } });
    if (existingUser)
      return res.status(400).json({ message: "Email already exists" });

    // Generate OTP
    const otp = Math.floor(100000 + Math.random() * 900000).toString();

    // Store user details temporarily with OTP
    otpStore[email] = {
      otp,
      payload: { firstName, lastName, email, phone, password, role },
    };

    // Clear OTP automatically after 10 minutes
    setTimeout(() => {
      delete otpStore[email];
    }, 10 * 60 * 1000); // 10 minutes

    // Send OTP email
    const transporter = nodemailer.createTransport({
      host: process.env.SMTP_HOST,
      port: parseInt(process.env.SMTP_PORT || "587"),
      secure: Number(process.env.SMTP_PORT) === 465,
      auth: {
        user: process.env.SMTP_USER,
        pass: process.env.SMTP_PASS, // Use Gmail App Password
      },
    });

    await transporter.sendMail({
      from: `"Virtual Education Hub Support" <${process.env.SMTP_USER}>`,
      to: email,
      subject: "Your VEH Registration OTP 🔒",
      html: `
    <div style="font-family: Arial, sans-serif; line-height: 1.5; color: #333;">
      <h2 style="color: #1976d2;">Hello ${firstName || email},</h2>
      <p>Thank you for registering with <strong>Virtual Education Hub</strong>. To complete your registration, please use the One-Time Password (OTP) below:</p>
      <div style="margin: 20px 0; padding: 15px; background-color: #f0f4ff; text-align: center; border-radius: 8px; font-size: 1.5rem; letter-spacing: 2px; font-weight: bold;">
        ${otp}
      </div>
      <p>This OTP is valid for <strong>10 minutes</strong>. Do not share it with anyone.</p>
      <p>If you did not request this, you can safely ignore this email.</p>
      <br/>
      <p>Best regards,<br/><strong>Virtual Education Hub Team</strong></p>
      <hr style="border:none; border-top:1px solid #eee; margin-top:20px;">
      <p style="font-size:0.85rem; color:#888;">Need help? Contact us at <a href="mailto:support@virtualeducationhub.org">support@virtualeducationhub.org</a></p>
    </div>
  `,
    });

    return res.json({ message: "OTP sent to email" });
  } catch (err) {
    console.error(err);
    return res.status(500).json({ message: "Server error" });
  }
};

// ----------------------
// Step 2: Verify OTP & Register
// ----------------------
exports.verifyOtp = async (req, res) => {
  try {
    const { email, otp } = req.body;

    if (!otpStore[email])
      return res.status(400).json({ message: "No OTP found for this email" });
    if (otpStore[email].otp !== otp)
      return res.status(400).json({ message: "Invalid OTP" });

    // Extract user data from store
    const { firstName, lastName, phone, password, role } =
      otpStore[email].payload;

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

    // Create user in DB
    const user = await prisma.user.create({
      data: {
        firstName,
        lastName,
        email,
        phone,
        password: hashedPassword,
        role: role || "student",
        status: "pending", // User is active immediately
      },
    });

    // Cleanup
    delete otpStore[email];// Notify all admins and accountants

    const staff = await prisma.user.findMany({
      where: { role: { in: ["admin", "accountant"] } },
      select: { id: true },
    });

    const staffIds = staff.map((u) => u.id);
    
    if (staffIds.length > 0) {
      const message = `New ${user.role} registered: "${user.firstName} ${user.lastName}" (Email: ${user.email}).`;
      await notifyManyUsers(req, staffIds, message, null); // system notification
    }

    return res
      .status(201)
      .json({ message: "User registered successfully", user });
  } catch (err) {
    console.error(err);
    return res.status(500).json({ message: "Server error" });
  }
};

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

    // Find user by email
    const user = await prisma.user.findUnique({ where: { email } });

    if (!user) {
      return res
        .status(400)
        .json({ message: "No account found with this email" });
    }

    // ---------- STAFF LOGIN (password required) ----------
    if (user.role !== "student") {
      if (!password) {
        return res.status(400).json({ message: "Password is required" });
      }

      const isMatch = await bcrypt.compare(password, user.password);
      if (!isMatch) {
        return res.status(400).json({ message: "Invalid email or password" });
      }
    }

    // ---------- STATUS CHECK (all users) ----------
    if (user.status === "pending") {
      return res.status(200).json({
        status: "pending",
        message: "Account under verification",
      });
    }

    if (user.status === "rejected") {
      return res.status(200).json({
        status: "rejected",
        message: "Registration rejected",
      });
    }

    // Update last login
    await prisma.user.update({
      where: { id: user.id },
      data: { lastLogin: new Date() },
    });

    // ----------------------------
    // ACCESS TOKEN (7 days)
    // ----------------------------
    const accessToken = jwt.sign(
      { id: user.id, role: user.role },
      process.env.JWT_SECRET,
      { expiresIn: "7d" }
    );

    // ----------------------------
    // REMEMBER ME → Refresh Token (staff only)
    // ----------------------------
    let refreshToken = null;

    if (rememberMe && user.role !== "student") {
      refreshToken = jwt.sign({ id: user.id }, process.env.JWT_SECRET, {
        expiresIn: "30d",
      });

      // Store hashed refresh token in DB
      const hashed = await bcrypt.hash(refreshToken, 10);
      await prisma.user.update({
        where: { id: user.id },
        data: {
          refreshToken: hashed,
          refreshTokenExpiresAt: new Date(
            Date.now() + 30 * 24 * 60 * 60 * 1000
          ),
        },
      });

      // Set cookie
      res.cookie("refreshToken", refreshToken, {
        httpOnly: true,
        secure: true,
        sameSite: "strict",
        maxAge: 30 * 24 * 60 * 60 * 1000,
      });
    }

    // Return response
    return res.status(200).json({
      message: "Login successful",
      token: accessToken,
      rememberMe: rememberMe || false,
      user: {
        id: user.id,
        firstName: user.firstName,
        lastName: user.lastName,
        role: user.role,
        status: user.status,
      },
    });
  } catch (err) {
    console.log("LOGIN ERROR:", err);
    return res.status(500).json({ message: "Server error" });
  }
};

exports.getMe = async (req, res) => {
  try {
    // Update lastActivity
    await prisma.user.update({
      where: { id: req.user.id },
      data: { lastActivity: new Date() },
    });

    res.json({
      user: {
        id: req.user.id,
        firstName: req.user.firstName,
        lastName: req.user.lastName,
        email: req.user.email,
        role: req.user.role,
        phone: req.user.phone,
        status: req.user.status,
      },
    });
  } catch (err) {
    console.log(err);
    res.status(500).json({ message: "Server error" });
  }
};

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

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

    // 1️⃣ Check if user exists
    const user = await prisma.user.findUnique({ where: { email } });
    if (!user) return res.status(404).json({ message: "Email not found." });

    // 2️⃣ Generate reset token (valid for 1 hour)
    const token = crypto.randomBytes(32).toString("hex");

    // Save token and expiry in database (10 minutes)
    await prisma.user.update({
      where: { id: user.id },
      data: {
        resetToken: token,
        resetTokenExpiry: new Date(Date.now() + 10 * 60 * 1000), // 10 minutes
      },
    });

    // 3️⃣ Create password reset link
    const resetLink = `${process.env.FRONTEND_URL}/reset-password?token=${token}`;

    // 4️⃣ Configure Nodemailer transporter
    const transporter = nodemailer.createTransport({
      host: process.env.SMTP_HOST,
      port: Number(process.env.SMTP_PORT),
      secure: Number(process.env.SMTP_PORT) === 465,
      auth: {
        user: process.env.SMTP_USER,
        pass: process.env.SMTP_PASS,
      },
    });

    // 5️⃣ Prepare email content
    const mailOptions = {
      from: `"Virtual Education Hub Support" <${process.env.SMTP_USER}>`,
      to: email,
      subject: "Password Reset Request",
      html: `
        <p>Hello ${user.firstName || user.email},</p>
        <p>We received a request to reset your LMS account password. Please click the link below to create a new password:</p>
        <p><a href="${resetLink}" style="background:#1976d2;color:white;padding:10px 20px;text-decoration:none;border-radius:5px;">Reset Password</a></p>
        <p><strong>Important:</strong> This link is valid for 10 minutes only. After that, you will need to request a new password reset.</p>
        <p>If you did not request this, you can safely ignore this email. Your password will remain unchanged.</p>
        <p>For any issues, contact our support team at <a href="mailto:support@virtualeducationhub.org">support@virtualeducationhub.org</a>.</p>
        <br>
        <p>Thanks,<br/>Virtual Education Hub Team</p>
      `,
    };

    // 6️⃣ Send email
    await transporter.sendMail(mailOptions);

    res.json({
      message:
        "A password reset link has been sent to your email. Please check your inbox. The link is valid for 10 minutes.",
    });
  } catch (err) {
    console.log(err);
    return res.status(500).json({ message: "Server error" });
  }
};

exports.resetPassword = async (req, res) => {
  try {
    const { token, password } = req.body;
    if (!token || !password)
      return res
        .status(400)
        .json({ message: "Token and password are required" });

    if (password.length < 6)
      return res
        .status(400)
        .json({ message: "Password must be at least 6 characters" });

    // Find user with token and valid expiry
    const user = await prisma.user.findFirst({
      where: { resetToken: token, resetTokenExpiry: { gt: new Date() } },
    });

    if (!user)
      return res.status(400).json({ message: "Invalid or expired token" });

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

    await prisma.user.update({
      where: { id: user.id },
      data: {
        password: hashedPassword,
        resetToken: null,
        resetTokenExpiry: null,
      },
    });

    const message = "Your password has been changed.";
    await notifyUser(req, user.id, message, null);

    res.json({ message: "Password reset successfully" });
  } catch (err) {
    console.log(err);
    res.status(500).json({ message: "Server error" });
  }
};

// --------------------------------------------
// REFRESH ACCESS TOKEN
// --------------------------------------------
exports.refreshAccessToken = async (req, res) => {
  const token = req.cookies.refreshToken;
  if (!token) return res.status(401).json({ message: "No refresh token" });

  let decoded;
  try {
    decoded = jwt.verify(token, process.env.JWT_SECRET);
  } catch {
    return res.status(401).json({ message: "Invalid refresh token" });
  }

  const user = await prisma.user.findUnique({ where: { id: decoded.id } });
  if (!user) return res.status(401).json({ message: "User not found" });

  const isValid = await bcrypt.compare(token, user.refreshToken || "");
  if (!isValid)
    return res.status(401).json({ message: "Token mismatch (DB invalid)" });

  const accessToken = jwt.sign(
    { id: user.id, role: user.role },
    process.env.JWT_SECRET,
    { expiresIn: "7d" }
  );

  return res.json({ accessToken });
};

// --------------------------------------------
// LOGOUT
// --------------------------------------------
exports.logout = async (req, res) => {
  try {
    res.clearCookie("refreshToken");

    await prisma.user.update({
      where: { id: req.user.id },
      data: {
        refreshToken: null,
        refreshTokenExpiresAt: null,
      },
    });

    return res.json({ message: "Logged out" });
  } catch (err) {
    console.log(err);
    return res.status(500).json({ message: "Logout failed" });
  }
};
