import { Prisma } from '@prisma/client';
import { prisma } from '../index';
import logger from '../utils/logger';

// Define NotificationType locally to avoid import issues
export type NotificationType = 'BOT_ASSIGNED';

export interface CreateNotificationInput {
  userId: string;
  title: string;
  message: string;
  type?: NotificationType;
  data?: Prisma.InputJsonValue;
}

export interface NotificationFilters {
  isRead?: boolean;
  type?: NotificationType;
}

export class NotificationService {
  /**
   * Create a new notification
   */
  static async createNotification(data: CreateNotificationInput) {
    const startTime = Date.now();
    
    logger.info('🔔 Creating notification', {
      userId: data.userId,
      title: data.title,
      type: data.type || 'BOT_ASSIGNED',
      requestTime: new Date().toISOString()
    });

    try {
      const notification = await prisma.notification.create({
        data: {
          userId: data.userId,
          title: data.title,
          message: data.message,
          type: data.type || 'BOT_ASSIGNED',
          data: data.data,
        },
        include: {
          user: {
            select: {
              id: true,
              name: true,
              email: true,
            },
          },
        },
      });

      const duration = Date.now() - startTime;
      logger.info('✅ Notification created successfully', {
        notificationId: notification.id,
        userId: data.userId,
        title: data.title,
        duration: `${duration}ms`,
      });

      return notification;
    } catch (error) {
      const duration = Date.now() - startTime;
      logger.error('❌ Failed to create notification', {
        userId: data.userId,
        title: data.title,
        error: error instanceof Error ? error.message : 'Unknown error',
        duration: `${duration}ms`,
      });
      throw error;
    }
  }

  /**
   * Get notifications for a user with pagination and filtering
   */
  static async getUserNotifications(
    userId: string,
    page: number = 1,
    limit: number = 20,
    filters: NotificationFilters = {}
  ) {
    const startTime = Date.now();
    
    logger.info('📋 Getting user notifications', {
      userId,
      page,
      limit,
      filters,
      requestTime: new Date().toISOString()
    });

    try {
      const where: any = {
        userId,
      };

      if (filters.isRead !== undefined) {
        where.isRead = filters.isRead;
      }

      if (filters.type) {
        where.type = filters.type;
      }

      const [notifications, total] = await Promise.all([
        prisma.notification.findMany({
          where,
          orderBy: {
            createdAt: 'desc',
          },
          skip: (page - 1) * limit,
          take: limit,
        }),
        prisma.notification.count({ where }),
      ]);

      const totalPages = Math.ceil(total / limit);

      const duration = Date.now() - startTime;
      logger.info('✅ User notifications retrieved successfully', {
        userId,
        page,
        limit,
        total,
        totalPages,
        duration: `${duration}ms`,
      });

      return {
        notifications,
        pagination: {
          page,
          limit,
          total,
          pages: totalPages,
        },
      };
    } catch (error) {
      const duration = Date.now() - startTime;
      logger.error('❌ Failed to get user notifications', {
        userId,
        page,
        limit,
        filters,
        error: error instanceof Error ? error.message : 'Unknown error',
        duration: `${duration}ms`,
      });
      throw error;
    }
  }

  /**
   * Get unread notifications count for a user
   */
  static async getUnreadCount(userId: string): Promise<number> {
    const startTime = Date.now();
    
    logger.info('🔢 Getting unread notifications count', {
      userId,
      requestTime: new Date().toISOString()
    });

    try {
      const count = await prisma.notification.count({
        where: {
          userId,
          isRead: false,
        },
      });

      const duration = Date.now() - startTime;
      logger.info('✅ Unread notifications count retrieved', {
        userId,
        count,
        duration: `${duration}ms`,
      });

      return count;
    } catch (error) {
      const duration = Date.now() - startTime;
      logger.error('❌ Failed to get unread notifications count', {
        userId,
        error: error instanceof Error ? error.message : 'Unknown error',
        duration: `${duration}ms`,
      });
      throw error;
    }
  }

  /**
   * Mark a notification as read
   */
  static async markAsRead(notificationId: string, userId: string) {
    const startTime = Date.now();
    
    logger.info('👁️ Marking notification as read', {
      notificationId,
      userId,
      requestTime: new Date().toISOString()
    });

    try {
      // Verify the notification belongs to the user
      const notification = await prisma.notification.findFirst({
        where: {
          id: notificationId,
          userId,
        },
      });

      if (!notification) {
        throw new Error('Notification not found or does not belong to user');
      }

      if (notification.isRead) {
        logger.info('ℹ️ Notification already marked as read', {
          notificationId,
          userId,
        });
        return notification;
      }

      const updatedNotification = await prisma.notification.update({
        where: {
          id: notificationId,
        },
        data: {
          isRead: true,
          readAt: new Date(),
        },
      });

      const duration = Date.now() - startTime;
      logger.info('✅ Notification marked as read successfully', {
        notificationId,
        userId,
        duration: `${duration}ms`,
      });

      return updatedNotification;
    } catch (error) {
      const duration = Date.now() - startTime;
      logger.error('❌ Failed to mark notification as read', {
        notificationId,
        userId,
        error: error instanceof Error ? error.message : 'Unknown error',
        duration: `${duration}ms`,
      });
      throw error;
    }
  }

  /**
   * Mark all notifications as read for a user
   */
  static async markAllAsRead(userId: string) {
    const startTime = Date.now();
    
    logger.info('👁️ Marking all notifications as read', {
      userId,
      requestTime: new Date().toISOString()
    });

    try {
      const result = await prisma.notification.updateMany({
        where: {
          userId,
          isRead: false,
        },
        data: {
          isRead: true,
          readAt: new Date(),
        },
      });

      const duration = Date.now() - startTime;
      logger.info('✅ All notifications marked as read successfully', {
        userId,
        updatedCount: result.count,
        duration: `${duration}ms`,
      });

      return result;
    } catch (error) {
      const duration = Date.now() - startTime;
      logger.error('❌ Failed to mark all notifications as read', {
        userId,
        error: error instanceof Error ? error.message : 'Unknown error',
        duration: `${duration}ms`,
      });
      throw error;
    }
  }

  /**
   * Create bot assignment notification
   */
  static async createBotAssignmentNotification(
    studentId: string,
    botName: string,
    grantedByName: string
  ) {
    const title = 'Bot Assigned';
    const message = `You have been assigned the bot "${botName}" by ${grantedByName}. You can now start practicing with it.`;

    return this.createNotification({
      userId: studentId,
      title,
      message,
      type: 'BOT_ASSIGNED',
      data: { botName, grantedByName },
    });
  }
}
