/**
 * Newsletter Subscription Model
 * Manages email subscriptions for blog updates and framework news
 */

const { ObjectId } = require('mongodb');
const { getCollection } = require('../utils/db.util');

class NewsletterSubscription {
  /**
   * Subscribe a new email address
   */
  static async subscribe(data) {
    const collection = await getCollection('newsletter_subscriptions');

    // Check if already subscribed
    const existing = await collection.findOne({
      email: data.email.toLowerCase()
    });

    if (existing) {
      // If previously unsubscribed, reactivate
      if (!existing.active) {
        await collection.updateOne(
          { _id: existing._id },
          {
            $set: {
              active: true,
              resubscribed_at: new Date(),
              updated_at: new Date()
            }
          }
        );
        return { ...existing, active: true };
      }
      // Already subscribed and active
      return existing;
    }

    // Create new subscription
    const subscription = {
      email: data.email.toLowerCase(),
      name: data.name || null,
      source: data.source || 'blog', // blog/homepage/docs/etc
      interests: data.interests || [], // e.g., ['framework-updates', 'case-studies', 'research']
      verification_token: this._generateToken(),
      verified: false, // Will be true after email verification
      active: true,
      subscribed_at: new Date(),
      created_at: new Date(),
      updated_at: new Date(),
      metadata: {
        ip_address: data.ip_address || null,
        user_agent: data.user_agent || null,
        referrer: data.referrer || null
      }
    };

    const result = await collection.insertOne(subscription);
    return { ...subscription, _id: result.insertedId };
  }

  /**
   * Verify email subscription
   */
  static async verify(token) {
    const collection = await getCollection('newsletter_subscriptions');

    const result = await collection.updateOne(
      { verification_token: token, active: true },
      {
        $set: {
          verified: true,
          verified_at: new Date(),
          updated_at: new Date()
        }
      }
    );

    return result.modifiedCount > 0;
  }

  /**
   * Unsubscribe an email address
   */
  static async unsubscribe(email, token = null) {
    const collection = await getCollection('newsletter_subscriptions');

    const filter = token
      ? { verification_token: token }
      : { email: email.toLowerCase() };

    const result = await collection.updateOne(
      filter,
      {
        $set: {
          active: false,
          unsubscribed_at: new Date(),
          updated_at: new Date()
        }
      }
    );

    return result.modifiedCount > 0;
  }

  /**
   * Find subscription by email
   */
  static async findByEmail(email) {
    const collection = await getCollection('newsletter_subscriptions');
    return await collection.findOne({ email: email.toLowerCase() });
  }

  /**
   * Find subscription by ID
   */
  static async findById(id) {
    const collection = await getCollection('newsletter_subscriptions');
    return await collection.findOne({ _id: new ObjectId(id) });
  }

  /**
   * List all subscriptions
   */
  static async list(options = {}) {
    const collection = await getCollection('newsletter_subscriptions');
    const {
      limit = 100,
      skip = 0,
      active = true,
      verified = null,
      source = null
    } = options;

    const filter = {};
    if (active !== null) filter.active = active;
    if (verified !== null) filter.verified = verified;
    if (source) filter.source = source;

    const subscriptions = await collection
      .find(filter)
      .sort({ created_at: -1 })
      .skip(skip)
      .limit(limit)
      .toArray();

    return subscriptions;
  }

  /**
   * Count subscriptions
   */
  static async count(filter = {}) {
    const collection = await getCollection('newsletter_subscriptions');
    return await collection.countDocuments(filter);
  }

  /**
   * Update subscription preferences
   */
  static async updatePreferences(email, preferences) {
    const collection = await getCollection('newsletter_subscriptions');

    const result = await collection.updateOne(
      { email: email.toLowerCase(), active: true },
      {
        $set: {
          interests: preferences.interests || [],
          name: preferences.name || null,
          updated_at: new Date()
        }
      }
    );

    return result.modifiedCount > 0;
  }

  /**
   * Get subscription statistics
   */
  static async getStats() {
    const collection = await getCollection('newsletter_subscriptions');

    const [
      totalSubscribers,
      activeSubscribers,
      verifiedSubscribers,
      recentSubscribers
    ] = await Promise.all([
      collection.countDocuments({}),
      collection.countDocuments({ active: true }),
      collection.countDocuments({ active: true, verified: true }),
      collection.countDocuments({
        active: true,
        created_at: { $gte: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000) }
      })
    ]);

    // Get source breakdown
    const sourceBreakdown = await collection.aggregate([
      { $match: { active: true } },
      { $group: { _id: '$source', count: { $sum: 1 } } }
    ]).toArray();

    return {
      total: totalSubscribers,
      active: activeSubscribers,
      verified: verifiedSubscribers,
      recent_30_days: recentSubscribers,
      by_source: sourceBreakdown.reduce((acc, item) => {
        acc[item._id || 'unknown'] = item.count;
        return acc;
      }, {})
    };
  }

  /**
   * Delete subscription (admin only)
   */
  static async delete(id) {
    const collection = await getCollection('newsletter_subscriptions');
    const result = await collection.deleteOne({ _id: new ObjectId(id) });
    return result.deletedCount > 0;
  }

  /**
   * Generate verification token
   */
  static _generateToken() {
    return require('crypto').randomBytes(32).toString('hex');
  }
}

module.exports = NewsletterSubscription;
