const { Notification, User } = require('../models');
const logger = require('../config/logger');
const { Op } = require('sequelize');
const { sequelize } = require('../config/database');

/**
 * Notification business logic
 */
class NotificationService {
  /**
   * Get unread count by type for a user
   * @param {string} userId - User ID
   * @returns {Promise<Object>} - Unread counts by type
   */
  static async getUnreadCounts(userId) {
    try {
      const counts = await Notification.findAll({
        attributes: [
          'type',
          [sequelize.fn('COUNT', sequelize.col('id')), 'count']
        ],
        where: { userId, isRead: false },
        group: ['type'],
        raw: true,
      });

      const result = { all: 0, system: 0, activity: 0, service: 0 };
      counts.forEach(item => {
        result[item.type] = parseInt(item.count);
        result.all += parseInt(item.count);
      });

      return result;
    } catch (error) {
      logger.error('Error getting unread counts:', error);
      throw error;
    }
  }
  /**
   * Create a notification
   * @param {Object} notificationData - Notification data
   * @returns {Promise<Object>} - Created notification
   */
  static async createNotification(notificationData) {
    try {
      const notification = await Notification.create({
        userId: notificationData.userId,
        type: notificationData.type,
        titleZh: notificationData.titleZh,
        titleEn: notificationData.titleEn,
        titleEs: notificationData.titleEs,
        contentZh: notificationData.contentZh,
        contentEn: notificationData.contentEn,
        contentEs: notificationData.contentEs,
        isRead: false,
      });

      logger.info(`Notification created for user ${notificationData.userId}`);
      return notification.toJSON();
    } catch (error) {
      logger.error('Error creating notification:', error);
      throw error;
    }
  }

  /**
   * Get notifications for a user with filtering and pagination
   * @param {string} userId - User ID
   * @param {Object} options - Query options
   * @returns {Promise<Object>} - Paginated notifications
   */
  static async getUserNotifications(userId, { page = 1, limit = 10, type } = {}) {
    try {
      const offset = (page - 1) * limit;

      const where = { userId };
      if (type) {
        where.type = type;
      }

      const { count, rows } = await Notification.findAndCountAll({
        where,
        order: [['createdAt', 'DESC']],
        limit: parseInt(limit),
        offset: parseInt(offset),
      });

      return {
        data: rows.map(notification => notification.toJSON()),
        pagination: {
          page: parseInt(page),
          limit: parseInt(limit),
          total: count,
          totalPages: Math.ceil(count / limit),
        },
      };
    } catch (error) {
      logger.error('Error fetching user notifications:', error);
      throw error;
    }
  }

  /**
   * Mark notification as read
   * @param {string} notificationId - Notification ID
   * @param {string} userId - User ID (for authorization)
   * @returns {Promise<Object>} - Updated notification
   */
  static async markAsRead(notificationId, userId) {
    try {
      const notification = await Notification.findOne({
        where: {
          id: notificationId,
          userId,
        },
      });

      if (!notification) {
        throw new Error('NOTIFICATION_NOT_FOUND');
      }

      // Only update if not already read
      if (!notification.isRead) {
        await notification.update({
          isRead: true,
          readAt: new Date(),
        });
      }

      logger.info(`Notification ${notificationId} marked as read`);
      return notification.toJSON();
    } catch (error) {
      logger.error(`Error marking notification ${notificationId} as read:`, error);
      throw error;
    }
  }

  /**
   * Mark all notifications as read for a user
   * @param {string} userId - User ID
   * @returns {Promise<number>} - Number of notifications updated
   */
  static async markAllAsRead(userId) {
    try {
      const [updatedCount] = await Notification.update(
        {
          isRead: true,
          readAt: new Date(),
        },
        {
          where: {
            userId,
            isRead: false,
          },
        }
      );

      logger.info(`${updatedCount} notifications marked as read for user ${userId}`);
      return updatedCount;
    } catch (error) {
      logger.error(`Error marking all notifications as read for user ${userId}:`, error);
      throw error;
    }
  }

  /**
   * Delete a notification
   * @param {string} notificationId - Notification ID
   * @param {string} userId - User ID (for authorization)
   * @returns {Promise<boolean>} - Success status
   */
  static async deleteNotification(notificationId, userId) {
    try {
      const notification = await Notification.findOne({
        where: {
          id: notificationId,
          userId,
        },
      });

      if (!notification) {
        throw new Error('NOTIFICATION_NOT_FOUND');
      }

      await notification.destroy();

      logger.info(`Notification ${notificationId} deleted`);
      return true;
    } catch (error) {
      logger.error(`Error deleting notification ${notificationId}:`, error);
      throw error;
    }
  }

  /**
   * Get localized notification content
   * @param {Object} notification - Notification object
   * @param {string} language - Language code (zh, en, es)
   * @returns {Object} - Localized notification
   */
  static getLocalizedNotification(notification, language = 'zh') {
    const languageSuffix = language.charAt(0).toUpperCase() + language.slice(1);
    
    return {
      id: notification.id,
      type: notification.type,
      title: notification[`title${languageSuffix}`] || notification.titleZh,
      content: notification[`content${languageSuffix}`] || notification.contentZh,
      isRead: notification.isRead,
      readAt: notification.readAt,
      createdAt: notification.createdAt,
      updatedAt: notification.updatedAt,
    };
  }
}

module.exports = NotificationService;
