/**
 * Notification Service
 * Handles sending notifications to users via multiple channels
 */

const db = require('../database/db');

class NotificationService {
  /**
   * Send notification to user
   * @param {string} userId - User ID to notify
   * @param {Object} notification - Notification details
   * @param {string} notification.type - Type of notification (email, in-app, both)
   * @param {string} notification.category - Category (payment, subscription, system, etc.)
   * @param {string} notification.title - Notification title
   * @param {string} notification.message - Notification message
   * @param {Object} notification.metadata - Additional metadata
   */
  async sendNotification(userId, notification) {
    const { type = 'in-app', category, title, message, metadata = {} } = notification;

    try {
      // Store notification in database
      const result = await db.query(
        `INSERT INTO notifications
         (user_id, type, category, title, message, metadata, read, created_at)
         VALUES ($1, $2, $3, $4, $5, $6, false, NOW())
         RETURNING *`,
        [userId, type, category, title, message, JSON.stringify(metadata)]
      );

      const savedNotification = result.rows[0];

      // If email notification requested, queue email
      if (type === 'email' || type === 'both') {
        await this.queueEmail(userId, notification);
      }

      // Emit real-time notification via Socket.io if available
      if (global.io) {
        global.io.to(`user:${userId}`).emit('notification', {
          id: savedNotification.id,
          category,
          title,
          message,
          metadata,
          createdAt: savedNotification.created_at
        });
      }

      return savedNotification;
    } catch (error) {
      console.error('Failed to send notification:', error);
      // Don't throw - notifications should be best-effort
      // Log error but don't fail the parent operation
      return null;
    }
  }

  /**
   * Queue email for sending
   * In production, this would integrate with an email service like SendGrid, SES, etc.
   */
  async queueEmail(userId, notification) {
    const { title, message, metadata = {} } = notification;

    try {
      // Get user email
      const userResult = await db.query(
        `SELECT email, username FROM users WHERE id = $1`,
        [userId]
      );

      if (userResult.rows.length === 0) {
        console.error(`User ${userId} not found for email notification`);
        return;
      }

      const user = userResult.rows[0];

      // Queue email in database (to be processed by email worker)
      await db.query(
        `INSERT INTO email_queue
         (user_id, recipient_email, subject, body, template, metadata, status, created_at)
         VALUES ($1, $2, $3, $4, $5, $6, 'pending', NOW())`,
        [
          userId,
          user.email,
          title,
          message,
          metadata.template || 'default',
          JSON.stringify({ ...metadata, username: user.username })
        ]
      );

      console.log(`Email queued for ${user.email}: ${title}`);
    } catch (error) {
      console.error('Failed to queue email:', error);
    }
  }

  /**
   * Send subscription downgrade notification
   */
  async notifySubscriptionDowngrade(userId) {
    return this.sendNotification(userId, {
      type: 'both',
      category: 'subscription',
      title: 'Subscription Cancelled',
      message: 'Your premium subscription has been cancelled and your account has been downgraded to the free tier. You still have access to premium features until the end of your billing period.',
      metadata: {
        template: 'subscription-downgrade',
        action: {
          label: 'Resubscribe',
          url: '/premium'
        }
      }
    });
  }

  /**
   * Send payment receipt
   */
  async notifyPaymentSuccess(userId, amount, invoiceId) {
    return this.sendNotification(userId, {
      type: 'email',
      category: 'payment',
      title: 'Payment Receipt',
      message: `Your payment of $${amount.toFixed(2)} has been processed successfully. Thank you for your continued subscription!`,
      metadata: {
        template: 'payment-receipt',
        amount,
        invoiceId,
        action: {
          label: 'View Invoice',
          url: `/billing/invoices/${invoiceId}`
        }
      }
    });
  }

  /**
   * Send payment failure notification
   */
  async notifyPaymentFailed(userId, amount, reason = 'Unknown') {
    return this.sendNotification(userId, {
      type: 'both',
      category: 'payment',
      title: 'Payment Failed',
      message: `We were unable to process your payment of $${amount.toFixed(2)}. Please update your payment method to continue your subscription.`,
      metadata: {
        template: 'payment-failed',
        amount,
        reason,
        action: {
          label: 'Update Payment Method',
          url: '/settings/billing'
        }
      }
    });
  }

  /**
   * Send trial ending notification
   */
  async notifyTrialEnding(userId, daysRemaining = 3) {
    return this.sendNotification(userId, {
      type: 'both',
      category: 'subscription',
      title: 'Trial Ending Soon',
      message: `Your premium trial will end in ${daysRemaining} days. Add a payment method to continue enjoying premium features without interruption.`,
      metadata: {
        template: 'trial-ending',
        daysRemaining,
        action: {
          label: 'Add Payment Method',
          url: '/settings/billing'
        }
      }
    });
  }

  /**
   * Get unread notifications for user
   */
  async getUnreadNotifications(userId, limit = 50) {
    const result = await db.query(
      `SELECT * FROM notifications
       WHERE user_id = $1 AND read = false
       ORDER BY created_at DESC
       LIMIT $2`,
      [userId, limit]
    );

    return result.rows;
  }

  /**
   * Mark notification as read
   */
  async markAsRead(notificationId, userId) {
    await db.query(
      `UPDATE notifications
       SET read = true, read_at = NOW()
       WHERE id = $1 AND user_id = $2`,
      [notificationId, userId]
    );
  }

  /**
   * Mark all notifications as read for user
   */
  async markAllAsRead(userId) {
    await db.query(
      `UPDATE notifications
       SET read = true, read_at = NOW()
       WHERE user_id = $1 AND read = false`,
      [userId]
    );
  }
}

module.exports = new NotificationService();
