const nodemailer = require("nodemailer");
const logger = require("../utils/logger");

const DEFAULT_WARNING_BALANCE = 50000;
const DEFAULT_CRITICAL_BALANCE = 10000;
const DEFAULT_COOLDOWN_MINUTES = 30;

const SUBJECTS = {
  lowBalance: "Smile Balance Low",
  automationFailure: "Automation Failed",
  criticalError: "Critical System Error",
  sessionExpired: "Smile Session Expired",
};

const lastSentAt = new Map();

function numberFromEnv(name, fallback) {
  const raw = process.env[name];
  if (!raw) return fallback;
  const value = Number(raw);
  return Number.isFinite(value) ? value : fallback;
}

function getConfig() {
  return {
    emailUser: process.env.EMAIL_USER,
    emailPass: process.env.EMAIL_PASS,
    adminEmail: process.env.ADMIN_EMAIL,
    warningBalance: numberFromEnv("EMAIL_WARNING_BALANCE", DEFAULT_WARNING_BALANCE),
    criticalBalance: numberFromEnv("EMAIL_CRITICAL_BALANCE", DEFAULT_CRITICAL_BALANCE),
    cooldownMinutes: numberFromEnv("EMAIL_COOLDOWN_MINUTES", DEFAULT_COOLDOWN_MINUTES),
  };
}

function validateConfig(config) {
  const missing = [];
  if (!config.emailUser) missing.push("EMAIL_USER");
  if (!config.emailPass) missing.push("EMAIL_PASS");
  if (!config.adminEmail) missing.push("ADMIN_EMAIL");

  if (missing.length > 0) {
    throw new Error(`Missing email environment variables: ${missing.join(", ")}`);
  }
}

function createTransporter(config = getConfig()) {
  validateConfig(config);
  return nodemailer.createTransport({
    service: "gmail",
    port: 587,
    secure: false,
    auth: {
      user: config.emailUser,
      pass: config.emailPass,
    },
    connectionTimeout: 10000,
    greetingTimeout: 10000,
    socketTimeout: 15000,
  });
}

function cooldownKey(type, key = "default") {
  return `${type}:${key}`;
}

function canSend(type, key, cooldownMinutes) {
  const now = Date.now();
  const previous = lastSentAt.get(cooldownKey(type, key));
  if (!previous) return true;
  return now - previous >= cooldownMinutes * 60 * 1000;
}

function markSent(type, key) {
  lastSentAt.set(cooldownKey(type, key), Date.now());
}

function formatDetails(details = {}) {
  return Object.entries(details)
    .filter(([, value]) => value !== undefined && value !== null && value !== "")
    .map(([key, value]) => `<tr><th>${escapeHtml(key)}</th><td>${escapeHtml(String(value))}</td></tr>`)
    .join("");
}

function escapeHtml(value) {
  return value
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;");
}

function buildEmailHtml(title, message, details) {
  const rows = formatDetails(details);
  return `
    <div style="font-family: Arial, sans-serif; color: #172033; line-height: 1.5;">
      <h2 style="margin: 0 0 12px;">${escapeHtml(title)}</h2>
      <p>${escapeHtml(message)}</p>
      ${
        rows
          ? `<table style="border-collapse: collapse; margin-top: 16px;">
              ${rows}
            </table>`
          : ""
      }
      <p style="color: #64748b; font-size: 12px; margin-top: 20px;">
        Sent by SmartCoin notification system at ${new Date().toISOString()}.
      </p>
    </div>
  `;
}

async function sendNotification(type, { subject, message, details = {}, cooldownKey: key = "default" }) {
  const config = getConfig();
  const cooldownMinutes = config.cooldownMinutes;

  if (!canSend(type, key, cooldownMinutes)) {
    logger.info("Email alert skipped due to cooldown", { alertType: type, cooldownKey: key });
    return { sent: false, skipped: true, reason: "cooldown" };
  }

  const transporter = createTransporter(config);
  const title = subject || SUBJECTS[type] || "SmartCoin Alert";

  try {
    const result = await transporter.sendMail({
      from: `"SmartCoin Alerts" <${config.emailUser}>`,
      to: config.adminEmail,
      subject: title,
      text: `${message}\n\n${JSON.stringify(details, null, 2)}`,
      html: buildEmailHtml(title, message, details),
    });

    markSent(type, key);
    logger.info("Email alert sent", {
      alertType: type,
      cooldownKey: key,
      messageId: result.messageId,
      accepted: result.accepted,
      rejected: result.rejected,
    });
    return { sent: true, messageId: result.messageId };
  } catch (error) {
    logger.error("Email alert failed", {
      alertType: type,
      cooldownKey: key,
      error: error.message,
    });
    throw error;
  }
}

async function sendLowBalanceAlert(balance, currency = "MMK") {
  const config = getConfig();
  const threshold = balance <= config.criticalBalance ? config.criticalBalance : config.warningBalance;
  const level = balance <= config.criticalBalance ? "critical" : "warning";

  if (balance > config.warningBalance) {
    return { sent: false, skipped: true, reason: "balance_above_threshold" };
  }

  return sendNotification("lowBalance", {
    message: `Smile.one balance is ${level}: ${balance.toLocaleString()} ${currency}.`,
    details: {
      balance,
      currency,
      level,
      threshold,
    },
    cooldownKey: level,
  });
}

async function sendAutomationFailureAlert(reason, details = {}) {
  return sendNotification("automationFailure", {
    message: reason || "Purchase automation failed.",
    details,
    cooldownKey: details.orderId || details.jobId || reason || "automation",
  });
}

async function sendCriticalErrorAlert(error, details = {}) {
  const message = error instanceof Error ? error.message : String(error || "Critical system error");
  return sendNotification("criticalError", {
    message,
    details: {
      ...details,
      stack: error instanceof Error ? error.stack : undefined,
    },
    cooldownKey: details.component || message,
  });
}

async function sendSessionExpiredAlert(account, details = {}) {
  return sendNotification("sessionExpired", {
    message: `Smile.one session expired${account ? ` for ${account}` : ""}.`,
    details: {
      account,
      ...details,
    },
    cooldownKey: account || "smile-session",
  });
}

module.exports = {
  sendNotification,
  sendLowBalanceAlert,
  sendAutomationFailureAlert,
  sendCriticalErrorAlert,
  sendSessionExpiredAlert,
};
