const express = require("express");
const router = express.Router();
const bcrypt = require("bcrypt");
const nodemailer = require("nodemailer");
const { pool } = require("../config/database");
const logger = require("../config/logger");
const rateLimit = require("express-rate-limit");

// SECURITY: Rate limiting for auth endpoints to prevent brute force
const authRateLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5, // 5 failed attempts per window before lockout
  skipSuccessfulRequests: true, // Only count failed attempts
  message: {
    success: false,
    message:
      "Too many failed login attempts, please try again after 15 minutes",
  },
  standardHeaders: true,
  legacyHeaders: false,
});

const signupRateLimiter = rateLimit({
  windowMs: 60 * 60 * 1000, // 1 hour
  max: 10, // 10 signups per hour per IP (increased for production)
  message: {
    success: false,
    message: "Too many signup attempts, please try again later",
  },
});

const resendCodeLimiter = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 3, // 3 resends per minute
  message: {
    success: false,
    message: "Please wait before requesting another code",
  },
});

// SECURITY: HTML escape function to prevent XSS in emails
const escapeHtml = (str) => {
  if (!str) return "";
  return String(str)
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#039;");
};

// SECURITY: Use crypto for secure verification code generation
const crypto = require("crypto");

// Email transporter configuration
let transporter = null;
if (process.env.SMTP_HOST && process.env.SMTP_USER && process.env.SMTP_PASS) {
  transporter = nodemailer.createTransport({
    host: process.env.SMTP_HOST,
    port: parseInt(process.env.SMTP_PORT) || 587,
    secure: process.env.SMTP_SECURE === "true",
    auth: {
      user: process.env.SMTP_USER,
      pass: process.env.SMTP_PASS,
    },
  });
}

// Generate 6-digit verification code using cryptographically secure random
function generateVerificationCode() {
  // SECURITY: Use crypto.randomInt for secure random number generation
  return crypto.randomInt(100000, 999999).toString();
}

// Send verification email
async function sendVerificationEmail(email, code, firstName) {
  if (!transporter) {
    logger.warn("SMTP not configured - verification code logged instead");
    logger.info(`🔐 Verification code for ${email}: ${code}`);
    return true;
  }

  // SECURITY: Escape user input to prevent XSS in emails
  const safeName = escapeHtml(firstName) || "there";
  const safeCode = String(code).replace(/[^0-9]/g, ""); // Only allow digits

  const mailOptions = {
    from: process.env.SMTP_FROM || '"Sky Art Shop" <noreply@skyartshop.com>',
    to: email,
    subject: "Verify your Sky Art Shop account",
    html: `
      <!DOCTYPE html>
      <html>
      <head>
        <style>
          body { font-family: 'Segoe UI', Arial, sans-serif; line-height: 1.6; color: #333; }
          .container { max-width: 600px; margin: 0 auto; padding: 20px; }
          .header { background: linear-gradient(135deg, #e91e63 0%, #9c27b0 100%); color: white; padding: 30px; text-align: center; border-radius: 10px 10px 0 0; }
          .content { background: #f9f9f9; padding: 30px; border-radius: 0 0 10px 10px; }
          .code { font-size: 36px; font-weight: bold; color: #e91e63; letter-spacing: 8px; text-align: center; padding: 20px; background: white; border-radius: 8px; margin: 20px 0; }
          .footer { text-align: center; color: #666; font-size: 12px; margin-top: 20px; }
        </style>
      </head>
      <body>
        <div class="container">
          <div class="header">
            <h1>🎨 Sky Art Shop</h1>
            <p>Welcome to our creative community!</p>
          </div>
          <div class="content">
            <p>Hi ${safeName}!</p>
            <p>Thank you for creating an account with Sky Art Shop. Please use the verification code below to complete your registration:</p>
            <div class="code">${safeCode}</div>
            <p>This code will expire in <strong>15 minutes</strong>.</p>
            <p>If you didn't create this account, please ignore this email.</p>
          </div>
          <div class="footer">
            <p>© 2025 Sky Art Shop. All rights reserved.</p>
            <p>Your one-stop shop for scrapbooking, journaling, and creative stationery.</p>
          </div>
        </div>
      </body>
      </html>
    `,
  };

  try {
    await transporter.sendMail(mailOptions);
    logger.info(`Verification email sent to ${email}`);
    return true;
  } catch (error) {
    logger.error("Error sending verification email:", error);
    // Still log code as fallback
    logger.info(`🔐 Verification code for ${email}: ${code}`);
    return false;
  }
}

// Customer auth middleware - session based
const requireCustomerAuth = (req, res, next) => {
  if (!req.session || !req.session.customerId) {
    return res
      .status(401)
      .json({ success: false, message: "Please login to continue" });
  }
  next();
};

// ===========================
// SIGNUP - Create new customer
// ===========================
router.post("/signup", signupRateLimiter, async (req, res) => {
  try {
    const {
      firstName,
      lastName,
      email,
      password,
      newsletterSubscribed = false,
    } = req.body;

    // Validation
    if (!firstName || !lastName || !email || !password) {
      return res.status(400).json({
        success: false,
        message:
          "All fields are required (firstName, lastName, email, password)",
      });
    }

    // SECURITY: Sanitize inputs to prevent XSS
    const sanitizedFirstName = firstName
      .replace(/[<>"'&]/g, "")
      .trim()
      .substring(0, 50);
    const sanitizedLastName = lastName
      .replace(/[<>"'&]/g, "")
      .trim()
      .substring(0, 50);

    // Email format validation
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(email)) {
      return res.status(400).json({
        success: false,
        message: "Please enter a valid email address",
      });
    }

    // Password strength validation
    if (password.length < 8) {
      return res.status(400).json({
        success: false,
        message: "Password must be at least 8 characters long",
      });
    }

    // Check if email already exists
    const existingCustomer = await pool.query(
      "SELECT id, email_verified FROM customers WHERE email = $1",
      [email.toLowerCase()],
    );

    if (existingCustomer.rows.length > 0) {
      const customer = existingCustomer.rows[0];

      // If email exists but not verified, allow re-registration
      if (!customer.email_verified) {
        // Generate new verification code
        const verificationCode = generateVerificationCode();
        const expiresAt = new Date(Date.now() + 15 * 60 * 1000); // 15 minutes
        const passwordHash = await bcrypt.hash(password, 12);

        await pool.query(
          `UPDATE customers 
           SET first_name = $1, last_name = $2, password_hash = $3, 
               verification_code = $4, verification_code_expires = $5,
               updated_at = CURRENT_TIMESTAMP
           WHERE email = $6`,
          [
            firstName,
            lastName,
            passwordHash,
            verificationCode,
            expiresAt,
            email.toLowerCase(),
          ],
        );

        // Send verification email
        await sendVerificationEmail(email, verificationCode, firstName);

        // Store email in session for verification step
        req.session.pendingVerificationEmail = email.toLowerCase();

        return res.json({
          success: true,
          message:
            "Verification code sent to your email. Please check your inbox.",
          requiresVerification: true,
        });
      }

      return res.status(400).json({
        success: false,
        message:
          "An account with this email already exists. Please login instead.",
      });
    }

    // Hash password
    const passwordHash = await bcrypt.hash(password, 12);

    // Generate verification code
    const verificationCode = generateVerificationCode();
    const expiresAt = new Date(Date.now() + 15 * 60 * 1000); // 15 minutes

    // Create customer
    await pool.query(
      `INSERT INTO customers (first_name, last_name, email, password_hash, verification_code, verification_code_expires, newsletter_subscribed)
       VALUES ($1, $2, $3, $4, $5, $6, $7)
       RETURNING id, email`,
      [
        firstName,
        lastName,
        email.toLowerCase(),
        passwordHash,
        verificationCode,
        expiresAt,
        newsletterSubscribed,
      ],
    );

    // Send verification email
    await sendVerificationEmail(email, verificationCode, firstName);

    // Store email in session for verification step
    req.session.pendingVerificationEmail = email.toLowerCase();

    logger.info(`New customer signup: ${email}`);

    res.json({
      success: true,
      message:
        "Account created! Please check your email for the verification code.",
      requiresVerification: true,
    });
  } catch (error) {
    logger.error("Signup error:", error);
    res.status(500).json({
      success: false,
      message: "Failed to create account. Please try again.",
    });
  }
});

// ===========================
// VERIFY EMAIL
// ===========================
router.post("/verify-email", async (req, res) => {
  try {
    const { email, code } = req.body;
    const emailToVerify =
      email?.toLowerCase() || req.session.pendingVerificationEmail;

    if (!emailToVerify || !code) {
      return res.status(400).json({
        success: false,
        message: "Email and verification code are required",
      });
    }

    const result = await pool.query(
      `SELECT id, first_name, last_name, email_verified, verification_code, verification_code_expires 
       FROM customers WHERE email = $1`,
      [emailToVerify],
    );

    if (result.rows.length === 0) {
      return res.status(404).json({
        success: false,
        message: "Account not found. Please sign up first.",
      });
    }

    const customer = result.rows[0];

    if (customer.email_verified) {
      return res.json({
        success: true,
        message: "Email already verified. You can now login.",
        alreadyVerified: true,
      });
    }

    if (customer.verification_code !== code) {
      return res.status(400).json({
        success: false,
        message: "Invalid verification code. Please try again.",
      });
    }

    if (new Date() > new Date(customer.verification_code_expires)) {
      return res.status(400).json({
        success: false,
        message: "Verification code has expired. Please request a new one.",
        expired: true,
      });
    }

    // Mark email as verified
    await pool.query(
      `UPDATE customers 
       SET email_verified = TRUE, verification_code = NULL, verification_code_expires = NULL,
           last_login = CURRENT_TIMESTAMP, login_count = 1
       WHERE id = $1`,
      [customer.id],
    );

    // Set session - auto-login after verification
    req.session.customerId = customer.id;
    req.session.customerEmail = emailToVerify;
    req.session.customerName = customer.first_name;
    delete req.session.pendingVerificationEmail;

    logger.info(`Email verified for customer: ${emailToVerify}`);

    res.json({
      success: true,
      message: "Email verified successfully! You are now logged in.",
      customer: {
        firstName: customer.first_name,
        lastName: customer.last_name,
        email: emailToVerify,
      },
    });
  } catch (error) {
    logger.error("Email verification error:", error);
    res.status(500).json({
      success: false,
      message: "Verification failed. Please try again.",
    });
  }
});

// ===========================
// RESEND VERIFICATION CODE
// ===========================
router.post("/resend-code", resendCodeLimiter, async (req, res) => {
  try {
    const { email } = req.body;
    const emailToVerify =
      email?.toLowerCase() || req.session.pendingVerificationEmail;

    if (!emailToVerify) {
      return res.status(400).json({
        success: false,
        message: "Email is required",
      });
    }

    const result = await pool.query(
      "SELECT id, first_name, email_verified FROM customers WHERE email = $1",
      [emailToVerify],
    );

    if (result.rows.length === 0) {
      return res.status(404).json({
        success: false,
        message: "Account not found. Please sign up first.",
      });
    }

    const customer = result.rows[0];

    if (customer.email_verified) {
      return res.json({
        success: true,
        message: "Email already verified. You can now login.",
        alreadyVerified: true,
      });
    }

    // Generate new verification code
    const verificationCode = generateVerificationCode();
    const expiresAt = new Date(Date.now() + 15 * 60 * 1000);

    await pool.query(
      `UPDATE customers 
       SET verification_code = $1, verification_code_expires = $2
       WHERE id = $3`,
      [verificationCode, expiresAt, customer.id],
    );

    // Send verification email
    await sendVerificationEmail(
      emailToVerify,
      verificationCode,
      customer.first_name,
    );

    res.json({
      success: true,
      message: "New verification code sent to your email.",
    });
  } catch (error) {
    logger.error("Resend code error:", error);
    res.status(500).json({
      success: false,
      message: "Failed to resend code. Please try again.",
    });
  }
});

// ===========================
// LOGIN
// ===========================
router.post("/login", authRateLimiter, async (req, res) => {
  try {
    const { email, password } = req.body;

    if (!email || !password) {
      return res.status(400).json({
        success: false,
        message: "Email and password are required",
      });
    }

    // SECURITY: Sanitize and validate email format
    const sanitizedEmail = email.toLowerCase().trim();
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(sanitizedEmail)) {
      // SECURITY: Use consistent timing to prevent enumeration
      await bcrypt.hash("dummy-password", 12);
      return res.status(401).json({
        success: false,
        message: "Invalid email or password",
      });
    }

    const result = await pool.query(
      `SELECT id, first_name, last_name, email, password_hash, email_verified, is_active
       FROM customers WHERE email = $1`,
      [sanitizedEmail],
    );

    if (result.rows.length === 0) {
      // SECURITY: Perform dummy hash to prevent timing attacks
      await bcrypt.hash("dummy-password", 12);
      return res.status(401).json({
        success: false,
        message: "Invalid email or password",
      });
    }

    const customer = result.rows[0];

    if (!customer.is_active) {
      return res.status(403).json({
        success: false,
        message: "This account has been deactivated. Please contact support.",
      });
    }

    if (!customer.email_verified) {
      // Store email for verification flow
      req.session.pendingVerificationEmail = email.toLowerCase();
      return res.status(403).json({
        success: false,
        message: "Please verify your email before logging in.",
        requiresVerification: true,
      });
    }

    // Verify password
    const isValidPassword = await bcrypt.compare(
      password,
      customer.password_hash,
    );
    if (!isValidPassword) {
      return res.status(401).json({
        success: false,
        message: "Invalid email or password",
      });
    }

    // Update last login
    await pool.query(
      `UPDATE customers SET last_login = CURRENT_TIMESTAMP, login_count = login_count + 1 WHERE id = $1`,
      [customer.id],
    );

    // Set session
    req.session.customerId = customer.id;
    req.session.customerEmail = customer.email;
    req.session.customerName = customer.first_name;

    logger.info(`Customer login: ${email}`);

    res.json({
      success: true,
      message: "Login successful",
      customer: {
        id: customer.id,
        firstName: customer.first_name,
        lastName: customer.last_name,
        email: customer.email,
      },
    });
  } catch (error) {
    logger.error("Login error:", error);
    res.status(500).json({
      success: false,
      message: "Login failed. Please try again.",
    });
  }
});

// ===========================
// LOGOUT
// ===========================
router.post("/logout", (req, res) => {
  req.session.customerId = null;
  req.session.customerEmail = null;
  req.session.customerName = null;
  res.json({ success: true, message: "Logged out successfully" });
});

// ===========================
// GET CURRENT SESSION
// ===========================
router.get("/session", async (req, res) => {
  try {
    if (!req.session.customerId) {
      return res.json({
        success: true,
        loggedIn: false,
      });
    }

    const result = await pool.query(
      `SELECT id, first_name, last_name, email, newsletter_subscribed, created_at
       FROM customers WHERE id = $1`,
      [req.session.customerId],
    );

    if (result.rows.length === 0) {
      req.session.customerId = null;
      return res.json({
        success: true,
        loggedIn: false,
      });
    }

    const customer = result.rows[0];
    res.json({
      success: true,
      loggedIn: true,
      customer: {
        id: customer.id,
        firstName: customer.first_name,
        lastName: customer.last_name,
        email: customer.email,
        newsletterSubscribed: customer.newsletter_subscribed,
        memberSince: customer.created_at,
      },
    });
  } catch (error) {
    logger.error("Session error:", error);
    res.status(500).json({ success: false, message: "Failed to get session" });
  }
});

// ===========================
// UPDATE PROFILE
// ===========================
router.put("/profile", requireCustomerAuth, async (req, res) => {
  try {
    const { firstName, lastName, newsletterSubscribed } = req.body;

    const updates = [];
    const values = [];
    let paramIndex = 1;

    if (firstName !== undefined) {
      updates.push(`first_name = $${paramIndex++}`);
      values.push(firstName);
    }
    if (lastName !== undefined) {
      updates.push(`last_name = $${paramIndex++}`);
      values.push(lastName);
    }
    if (newsletterSubscribed !== undefined) {
      updates.push(`newsletter_subscribed = $${paramIndex++}`);
      values.push(newsletterSubscribed);
    }

    if (updates.length === 0) {
      return res.status(400).json({
        success: false,
        message: "No fields to update",
      });
    }

    values.push(req.session.customerId);

    await pool.query(
      `UPDATE customers SET ${updates.join(", ")} WHERE id = $${paramIndex}`,
      values,
    );

    res.json({ success: true, message: "Profile updated successfully" });
  } catch (error) {
    logger.error("Profile update error:", error);
    res
      .status(500)
      .json({ success: false, message: "Failed to update profile" });
  }
});

module.exports = router;
module.exports.requireCustomerAuth = requireCustomerAuth;
