import { prisma } from '@/lib/prisma';

export type NotificationType = 
  | 'PROJECT_COMPLETED'
  | 'PROJECT_COMPLETED_BY_CLIENT' 
  | 'PROJECT_CANCELLED'
  | 'PROJECT_CANCELLED_BY_CLIENT'
  | 'BID_ACCEPTED'
  | 'BID_REJECTED'
  | 'PROJECT_AWARDED'
  | 'REVIEW_RECEIVED'
  | 'PAYMENT_RECEIVED'
  | 'PAYMENT_RELEASED'
  | 'PROJECT_UPDATE_REQUESTED'
  | 'PROJECT_UPDATE_APPROVED'
  | 'PROJECT_UPDATE_REJECTED'
  | 'MESSAGE_RECEIVED';

interface NotificationData {
  projectId?: string;
  projectTitle?: string;
  bidId?: string;
  freelancerId?: string;
  clientId?: string;
  amount?: number;
  currency?: string;
  deliverableCount?: number;
  completedAt?: string;
  cancelReason?: string;
  rating?: number;
  [key: string]: any;
}

interface CreateNotificationParams {
  userId: string;
  type: NotificationType;
  title: string;
  message: string;
  data?: NotificationData;
}

export class NotificationService {
  /**
   * Creates a notification in the database
   */
  static async createNotification({
    userId,
    type,
    title,
    message,
    data = {}
  }: CreateNotificationParams) {
    try {
      if (!prisma) {
        console.error('Prisma not available for notification creation');
        return null;
      }

      const notification = await prisma.notification.create({
        data: {
          userId,
          type,
          title,
          message,
          data: JSON.stringify({
            ...data,
            createdAt: new Date().toISOString(),
            type
          }),
          isRead: false,
          createdAt: new Date()
        }
      });

      console.log(`✅ Notification created: ${type} for user ${userId}`);
      return notification;
    } catch (error) {
      console.error('Failed to create notification:', error);
      return null;
    }
  }

  /**
   * Creates project completion notification for client when freelancer completes
   */
  static async notifyProjectCompletedByFreelancer(
    clientId: string,
    freelancerName: string,
    projectTitle: string,
    projectId: string,
    deliverableCount: number = 0
  ) {
    return this.createNotification({
      userId: clientId,
      type: 'PROJECT_COMPLETED',
      title: 'Project Completed',
      message: `${freelancerName} has completed the project "${projectTitle}"${deliverableCount > 0 ? ` and delivered ${deliverableCount} deliverable(s)` : ''}. Please review the work and provide feedback.`,
      data: {
        projectId,
        projectTitle,
        freelancerName,
        deliverableCount,
        completedAt: new Date().toISOString(),
        actionRequired: true,
        redirectTo: `/client/my-projects/${projectId}`
      }
    });
  }

  /**
   * Creates project completion notification for freelancer when client marks complete
   */
  static async notifyProjectCompletedByClient(
    freelancerId: string,
    clientName: string,
    projectTitle: string,
    projectId: string,
    clientNote?: string
  ) {
    return this.createNotification({
      userId: freelancerId,
      type: 'PROJECT_COMPLETED_BY_CLIENT',
      title: 'Project Marked Complete',
      message: `${clientName} has marked the project "${projectTitle}" as complete.${clientNote ? ' Note: ' + clientNote : ''} You can now submit your review.`,
      data: {
        projectId,
        projectTitle,
        clientName,
        clientNote,
        completedAt: new Date().toISOString(),
        actionRequired: true,
        redirectTo: `/freelancer/review/${projectId}`
      }
    });
  }

  /**
   * Creates project cancellation notification for freelancer when client cancels
   */
  static async notifyProjectCancelledByClient(
    freelancerId: string,
    clientName: string,
    projectTitle: string,
    projectId: string,
    cancelReason: string,
    refundRequested: boolean = false
  ) {
    return this.createNotification({
      userId: freelancerId,
      type: 'PROJECT_CANCELLED_BY_CLIENT',
      title: 'Project Cancelled',
      message: `${clientName} has cancelled the project "${projectTitle}". Reason: ${cancelReason}${refundRequested ? ' A refund has been requested.' : ''}`,
      data: {
        projectId,
        projectTitle,
        clientName,
        cancelReason,
        refundRequested,
        cancelledAt: new Date().toISOString(),
        actionRequired: false,
        redirectTo: `/freelancer/projects/cancelled/${projectId}`
      }
    });
  }

  /**
   * Creates project cancellation notification for client (if freelancer cancels)
   */
  static async notifyProjectCancelledByFreelancer(
    clientId: string,
    freelancerName: string,
    projectTitle: string,
    projectId: string,
    cancelReason: string
  ) {
    return this.createNotification({
      userId: clientId,
      type: 'PROJECT_CANCELLED',
      title: 'Project Cancelled',
      message: `${freelancerName} has cancelled the project "${projectTitle}". Reason: ${cancelReason}`,
      data: {
        projectId,
        projectTitle,
        freelancerName,
        cancelReason,
        cancelledAt: new Date().toISOString(),
        actionRequired: true,
        redirectTo: `/client/my-projects/${projectId}`
      }
    });
  }

  /**
   * Creates bid acceptance notification
   */
  static async notifyBidAccepted(
    freelancerId: string,
    clientName: string,
    projectTitle: string,
    projectId: string,
    bidAmount: number,
    currency: string
  ) {
    return this.createNotification({
      userId: freelancerId,
      type: 'BID_ACCEPTED',
      title: 'Bid Accepted!',
      message: `Congratulations! ${clientName} has accepted your bid of ${currency} ${bidAmount} for "${projectTitle}". The project has started.`,
      data: {
        projectId,
        projectTitle,
        clientName,
        bidAmount,
        currency,
        acceptedAt: new Date().toISOString(),
        actionRequired: true,
        redirectTo: `/freelancer/projects/ongoing/${projectId}`
      }
    });
  }

  /**
   * Creates bid rejection notification
   */
  static async notifyBidRejected(
    freelancerId: string,
    clientName: string,
    projectTitle: string,
    projectId: string,
    rejectionReason?: string
  ) {
    return this.createNotification({
      userId: freelancerId,
      type: 'BID_REJECTED',
      title: 'Bid Not Selected',
      message: `${clientName} has chosen another freelancer for "${projectTitle}".${rejectionReason ? ` Reason: ${rejectionReason}` : ''} Keep applying to more projects!`,
      data: {
        projectId,
        projectTitle,
        clientName,
        rejectionReason,
        rejectedAt: new Date().toISOString(),
        actionRequired: false,
        redirectTo: `/freelancer/projects`
      }
    });
  }

  /**
   * Creates review received notification
   */
  static async notifyReviewReceived(
    userId: string,
    reviewerName: string,
    projectTitle: string,
    projectId: string,
    rating: number,
    reviewType: 'client' | 'freelancer'
  ) {
    return this.createNotification({
      userId,
      type: 'REVIEW_RECEIVED',
      title: 'New Review Received',
      message: `${reviewerName} has left you a ${rating}-star review for the project "${projectTitle}". Check it out!`,
      data: {
        projectId,
        projectTitle,
        reviewerName,
        rating,
        reviewType,
        reviewedAt: new Date().toISOString(),
        actionRequired: false,
        redirectTo: reviewType === 'client' ? `/client/my-projects/${projectId}` : `/freelancer/projects/completed/${projectId}`
      }
    });
  }

  /**
   * Mark notification as read
   */
  static async markAsRead(notificationId: string) {
    try {
      if (!prisma) return null;
      
      return await prisma.notification.update({
        where: { id: notificationId },
        data: {
          isRead: true,
          readAt: new Date()
        }
      });
    } catch (error) {
      console.error('Failed to mark notification as read:', error);
      return null;
    }
  }

  /**
   * Mark all notifications as read for a user
   */
  static async markAllAsRead(userId: string) {
    try {
      if (!prisma) return null;
      
      return await prisma.notification.updateMany({
        where: {
          userId,
          isRead: false
        },
        data: {
          isRead: true,
          readAt: new Date()
        }
      });
    } catch (error) {
      console.error('Failed to mark all notifications as read:', error);
      return null;
    }
  }

  /**
   * Get unread notification count for a user
   */
  static async getUnreadCount(userId: string): Promise<number> {
    try {
      if (!prisma) return 0;
      
      const count = await prisma.notification.count({
        where: {
          userId,
          isRead: false,
          type: {
            not: 'MESSAGE_RECEIVED' // Exclude message notifications
          }
        }
      });
      
      return count;
    } catch (error) {
      console.error('Failed to get unread notification count:', error);
      return 0;
    }
  }
}

export default NotificationService;