/**
 * Backup Notification Settings
 *
 * Read from `superAdmin.panelSettings.backupNotifications`, the same place the
 * feature-request notification config lives. Recipients, subjects, branding and
 * retry behaviour are all editable from the Super Admin panel — nothing here is
 * hardcoded at a call site and nothing needs a redeploy to change.
 *
 * SMTP credentials are deliberately NOT part of this: those already live in the
 * `SmtpConfig` collection behind Super Admin → Email Configuration, and backup
 * emails go out through the same transport as every other system email.
 */

import { getModels } from '../../models';

export interface BackupNotificationSettings {
  /** Master switch. Off → no backup email is ever sent. */
  enabled: boolean;
  notifyOnSuccess: boolean;
  notifyOnFailure: boolean;
  /** Platform-wide recipients, managed in the Super Admin UI. */
  recipients: string[];
  /** Also notify the addresses configured on each company's backup settings. */
  includeCompanyRecipients: boolean;
  /**
   * Also notify whoever triggered the backup.
   *
   * Manual backups only — an automatic one is recorded against `system`, so
   * there is no person to tell and configured recipients remain the only way
   * scheduled backups get reported. On by default: the person who just pressed
   * the button is the one most likely to want the result, and making them ask
   * an administrator to add them first is a poor default.
   */
  notifyBackupCreator: boolean;
  /** Blank → the default SMTP configuration's sender identity is used. */
  senderName: string;
  senderEmail: string;
  /** `{{token}}` placeholders are rendered the same way as in the body. */
  subjectSuccess: string;
  subjectFailure: string;
  /** System template slugs — editable under Super Admin → Email Templates. */
  templateSuccess: string;
  templateFailure: string;
  footerHtml: string;
  logoUrl: string;
  /** Include host/platform details. Off by default — it is infrastructure detail. */
  includeServerInfo: boolean;
  retry: {
    maxAttempts: number;
    baseDelayMs: number;
  };
}

export const DEFAULT_BACKUP_NOTIFICATIONS: BackupNotificationSettings = {
  enabled: false,
  notifyOnSuccess: true,
  notifyOnFailure: true,
  recipients: [],
  includeCompanyRecipients: true,
  notifyBackupCreator: true,
  senderName: '',
  senderEmail: '',
  subjectSuccess: 'Backup completed: {{backup_name}}',
  subjectFailure: 'Backup FAILED: {{backup_name}}',
  templateSuccess: 'backup-success',
  templateFailure: 'backup-failure',
  footerHtml: '',
  logoUrl: '',
  includeServerInfo: false,
  retry: {
    maxAttempts: 3,
    baseDelayMs: 2000,
  },
};

const CACHE_TTL_MS = 60_000;
let cached: BackupNotificationSettings | null = null;
let cachedAt = 0;

export function invalidateBackupNotificationSettingsCache(): void {
  cached = null;
  cachedAt = 0;
}

function clamp(value: any, min: number, max: number, fallback: number): number {
  const n = Number(value);
  if (!Number.isFinite(n)) return fallback;
  return Math.min(Math.max(Math.floor(n), min), max);
}

function cleanString(value: any, fallback: string, maxLength = 200): string {
  return typeof value === 'string' ? value.trim().slice(0, maxLength) : fallback;
}

/**
 * Keep only well-formed, de-duplicated addresses.
 *
 * Filtered here as well as at the API validator because this is a free-form
 * `Mixed` field: one malformed address written by an older build or a direct
 * edit would otherwise make nodemailer reject the whole recipient list, losing
 * the notification for everyone on it.
 */
export function sanitiseRecipients(value: any): string[] {
  if (!Array.isArray(value)) return [];

  const seen = new Set<string>();
  const out: string[] = [];

  for (const entry of value) {
    if (typeof entry !== 'string') continue;
    const email = entry.trim().toLowerCase();
    if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) continue;
    if (seen.has(email)) continue;
    seen.add(email);
    out.push(email);
  }

  return out;
}

export function normaliseBackupNotificationSettings(raw: any): BackupNotificationSettings {
  const d = DEFAULT_BACKUP_NOTIFICATIONS;
  if (!raw || typeof raw !== 'object') return { ...d, recipients: [] };

  const retry = raw.retry || {};

  return {
    enabled: raw.enabled === true,
    notifyOnSuccess: raw.notifyOnSuccess !== false,
    notifyOnFailure: raw.notifyOnFailure !== false,
    recipients: sanitiseRecipients(raw.recipients),
    includeCompanyRecipients: raw.includeCompanyRecipients !== false,
    notifyBackupCreator: raw.notifyBackupCreator !== false,
    senderName: cleanString(raw.senderName, d.senderName, 120),
    senderEmail: cleanString(raw.senderEmail, d.senderEmail, 200).toLowerCase(),
    subjectSuccess: cleanString(raw.subjectSuccess, d.subjectSuccess, 300) || d.subjectSuccess,
    subjectFailure: cleanString(raw.subjectFailure, d.subjectFailure, 300) || d.subjectFailure,
    templateSuccess: cleanString(raw.templateSuccess, d.templateSuccess, 80) || d.templateSuccess,
    templateFailure: cleanString(raw.templateFailure, d.templateFailure, 80) || d.templateFailure,
    // Admin-authored and email-only — never injected into the app's own DOM.
    footerHtml: typeof raw.footerHtml === 'string' ? raw.footerHtml.slice(0, 5000) : d.footerHtml,
    logoUrl: cleanString(raw.logoUrl, d.logoUrl, 500),
    includeServerInfo: raw.includeServerInfo === true,
    retry: {
      maxAttempts: clamp(retry.maxAttempts, 1, 10, d.retry.maxAttempts),
      baseDelayMs: clamp(retry.baseDelayMs, 0, 60_000, d.retry.baseDelayMs),
    },
  };
}

/**
 * The active configuration.
 *
 * Never throws: on any read failure the defaults apply, which means notifications
 * are treated as disabled. A backup must never fail because its notification
 * config could not be loaded.
 */
export async function getBackupNotificationSettings(): Promise<BackupNotificationSettings> {
  const now = Date.now();
  if (cached && now - cachedAt < CACHE_TTL_MS) return cached;

  try {
    const { User } = getModels();
    const superAdmin = await User.findOne({ role: 'super-admin' })
      .select('panelSettings')
      .lean();

    cached = normaliseBackupNotificationSettings((superAdmin as any)?.panelSettings?.backupNotifications);
    cachedAt = now;
    return cached;
  } catch (err: any) {
    console.warn('[BackupNotifications] Failed to load settings, treating as disabled:', err?.message);
    return { ...DEFAULT_BACKUP_NOTIFICATIONS, recipients: [] };
  }
}
