import prisma from "~/server/utils/prisma";
import { processEmailQueue } from "~/server/utils/emailService";

// Basic input validation function
function validateBasicInput(body) {
  const errors = [];

  // Required fields validation
  if (!body.title || body.title.trim() === '') {
    errors.push('Title is required');
  }

  if (!body.type || !['single', 'bulk'].includes(body.type)) {
    errors.push('Type must be either "single" or "bulk"');
  }

  if (!body.priority || !['low', 'medium', 'high', 'critical'].includes(body.priority)) {
    errors.push('Priority must be one of: low, medium, high, critical');
  }

  if (!body.category || body.category.trim() === '') {
    errors.push('Category is required');
  }

  if (!body.channels || !Array.isArray(body.channels) || body.channels.length === 0) {
    errors.push('At least one channel is required');
  } else {
    const validChannels = ['email', 'push', 'sms'];
    const invalidChannels = body.channels.filter(channel => !validChannels.includes(channel));
    if (invalidChannels.length > 0) {
      errors.push(`Invalid channels: ${invalidChannels.join(', ')}`);
    }
  }

  if (!body.deliveryType || !['immediate', 'scheduled'].includes(body.deliveryType)) {
    errors.push('Delivery type must be either "immediate" or "scheduled"');
  }

  if (!body.audienceType || !['all', 'specific', 'segmented'].includes(body.audienceType)) {
    errors.push('Audience type must be one of: all, specific, segmented');
  }

  if (!body.contentType || !['new', 'template'].includes(body.contentType)) {
    errors.push('Content type must be either "new" or "template"');
  }

  // Conditional validations
  if (body.deliveryType === 'scheduled' && !body.scheduledAt) {
    errors.push('Scheduled date is required for scheduled notifications');
  }

  if (body.channels && body.channels.includes('email') && !body.emailSubject) {
    errors.push('Email subject is required when email channel is selected');
  }

  // Content validations
  if (body.contentType === 'template' && !body.selectedTemplate) {
    errors.push('Template selection is required when using template content');
  }

  if (body.contentType === 'new') {
    if (body.channels && body.channels.includes('email') && !body.emailContent) {
      errors.push('Email content is required when using email channel with new content');
    }

    if (body.channels && body.channels.includes('push') && (!body.pushTitle || !body.pushBody)) {
      errors.push('Push title and body are required when using push channel with new content');
    }
  }

  // Audience validations
  if (body.audienceType === 'specific' && (!body.specificUsers || body.specificUsers.trim() === '')) {
    errors.push('Specific users are required when audience type is specific');
  }

  if (body.audienceType === 'segmented' && (!body.userSegments || body.userSegments.length === 0)) {
    errors.push('At least one user segment is required when audience type is segmented');
  }

  return errors;
}

// Simple audience count estimation
async function estimateAudienceCount(audienceData, tx) {
  try {
    if (audienceData.audienceType === 'all') {
      // For testing, return 1 (since we're using test recipients)
      return 1;
    } else if (audienceData.audienceType === 'specific') {
      // Count lines in specificUsers
      const userLines = audienceData.specificUsers
        .split('\n')
        .filter(line => line.trim() !== '');
      return userLines.length;
    } else if (audienceData.audienceType === 'segmented') {
      // For segmented audience, return an estimate
      // In a real implementation, this would query based on segments
      return audienceData.userSegments?.length || 0;
    }
    return 0;
  } catch (error) {
    console.error("Error estimating audience count:", error);
    return 0;
  }
}

export default defineEventHandler(async (event) => {
  try {
    // Read and validate request body
    const body = await readBody(event);
    
    console.log("Request body:", body);

    // Basic input validation
    const validationErrors = validateBasicInput(body);
    if (validationErrors.length > 0) {
      throw createError({
        statusCode: 400,
        statusMessage: "Validation failed",
        data: {
          errors: validationErrors
        }
      });
    }

    // Get current user (assuming auth middleware provides this)
    const user = event.context.user;
    if (!user || !user.userID) {
      throw createError({
        statusCode: 401,
        statusMessage: "Authentication required",
      });
    }

    // Set default values for optional fields
    const notificationData = {
      title: body.title,
      type: body.type,
      priority: body.priority,
      category: body.category,
      channels: body.channels,
      emailSubject: body.emailSubject || null,
      deliveryType: body.deliveryType,
      scheduledAt: body.scheduledAt || null,
      timezone: body.timezone || 'UTC',
      audienceType: body.audienceType,
      specificUsers: body.specificUsers || null,
      userSegments: body.userSegments || [],
      excludeUnsubscribed: body.excludeUnsubscribed !== false, // default true
      contentType: body.contentType,
      selectedTemplate: body.selectedTemplate || null,
      emailContent: body.emailContent || null,
      callToActionText: body.callToActionText || null,
      callToActionUrl: body.callToActionUrl || null,
      pushTitle: body.pushTitle || null,
      pushBody: body.pushBody || null,
    };

    // Use Prisma transaction for consistency
    const result = await prisma.$transaction(async (tx) => {
      // 1. Get category
      const category = await tx.notification_categories.findFirst({
        where: { value: notificationData.category },
      });

      if (!category) {
        throw createError({
          statusCode: 400,
          statusMessage: "Invalid category",
        });
      }

      // 2. Get template data if using template
      let templateData = null;
      if (notificationData.contentType === "template") {
        templateData = await tx.notification_templates.findFirst({
          where: {
            value: notificationData.selectedTemplate,
            is_active: true,
          },
        });

        if (!templateData) {
          throw createError({
            statusCode: 400,
            statusMessage: "Invalid or inactive template",
          });
        }
      }

      // 3. Calculate estimated reach
      const estimatedReach = await estimateAudienceCount(notificationData, tx);

      // 4. Create notification record
      const notification = await tx.notifications.create({
        data: {
          title: notificationData.title,
          type: notificationData.type,
          priority: notificationData.priority,
          category_id: category.id,
          delivery_type: notificationData.deliveryType,
          scheduled_at: notificationData.scheduledAt ? new Date(notificationData.scheduledAt) : null,
          timezone: notificationData.timezone,
          enable_tracking: true, // Simplified: always enable tracking
          audience_type: notificationData.audienceType,
          specific_users: notificationData.specificUsers,
          exclude_unsubscribed: notificationData.excludeUnsubscribed,
          respect_do_not_disturb: true, // Simplified: always respect DND
          content_type: notificationData.contentType,
          template_id: templateData?.id || null,
          email_subject: notificationData.emailSubject || templateData?.subject || null,
          email_content: notificationData.emailContent || templateData?.email_content || null,
          call_to_action_text: notificationData.callToActionText || null,
          call_to_action_url: notificationData.callToActionUrl || null,
          push_title: notificationData.pushTitle || templateData?.push_title || null,
          push_body: notificationData.pushBody || templateData?.push_body || null,
          estimated_reach: estimatedReach,
          created_by: user.userID.toString(),
          status: notificationData.deliveryType === "immediate" ? "sending" : "scheduled",
        },
      });

      // 5. Insert notification channels
      await tx.notification_channels.createMany({
        data: notificationData.channels.map((channel) => ({
          notification_id: notification.id,
          channel_type: channel,
        })),
      });

      // 6. Insert user segments if segmented audience
      if (notificationData.audienceType === "segmented" && notificationData.userSegments?.length > 0) {
        for (const segment of notificationData.userSegments) {
          const segmentData = await tx.user_segments.findFirst({
            where: {
              value: segment,
              is_active: true,
            },
          });

          if (segmentData) {
            await tx.notification_user_segments.create({
              data: {
                notification_id: notification.id,
                segment_id: segmentData.id,
              },
            });
          }
        }
      }

      // 7. Add recipients to notification_recipients table and queue them
      // First, determine who will receive the notification
      const recipientsList = [];
      
      // Get users based on audience type
      if (notificationData.audienceType === 'all') {
        // For testing, use the configured sender email
        const senderEmail = process.env.SMTP_USER || 'test@example.com';
        recipientsList.push({
          user_id: "test-user-1",
          email: senderEmail, // Use your email for testing
        });
      } 
      else if (notificationData.audienceType === 'specific' && notificationData.specificUsers) {
        // Parse specific users from the text field (email addresses or IDs)
        const userIds = notificationData.specificUsers
          .split('\n')
          .filter(line => line.trim() !== '')
          .map(line => line.trim());
          
        // For each specified user, add to recipients
        for (const userId of userIds) {
          const isEmail = userId.includes('@');
          recipientsList.push({
            user_id: isEmail ? userId.split('@')[0] : userId, // Extract username or use ID
            email: isEmail ? userId : `${userId}@example.com`, // Use provided email or generate fake one
          });
        }
      }
      else if (notificationData.audienceType === 'segmented' && notificationData.userSegments?.length > 0) {
        // For demo purposes, just add placeholder users for each segment
        for (let i = 0; i < notificationData.userSegments.length; i++) {
          const segmentValue = notificationData.userSegments[i];
          recipientsList.push({
            user_id: `${segmentValue}-user-${i+1}`,
            email: `${segmentValue}${i+1}@example.com`,
          });
        }
      }
      
      // Create recipients and queue entries using batch inserts for better performance
      console.log(`📦 Processing ${recipientsList.length} recipients across ${notificationData.channels.length} channel(s)...`);

      // Prepare batch data for recipients
      const recipientsData = [];
      for (const recipient of recipientsList) {
        for (const channel of notificationData.channels) {
          recipientsData.push({
            notification_id: notification.id,
            user_id: recipient.user_id,
            email: channel === 'email' ? recipient.email : null,
            channel_type: channel,
            status: 'pending',
          });
        }
      }

      // Batch insert all recipients at once
      await tx.notification_recipients.createMany({
        data: recipientsData,
      });

      // Fetch created recipients to get their IDs for queue
      const createdRecipients = await tx.notification_recipients.findMany({
        where: { notification_id: notification.id },
        orderBy: { id: 'asc' }
      });

      // Determine when this notification should be scheduled
      let scheduledFor;
      if (notificationData.deliveryType === 'immediate') {
        scheduledFor = new Date(Date.now() + 60000); // 1 minute from now
      } else if (notificationData.deliveryType === 'scheduled' && notificationData.scheduledAt) {
        scheduledFor = new Date(notificationData.scheduledAt);
      } else {
        scheduledFor = new Date(Date.now() + 300000); // Fallback - 5 minutes from now
      }

      const priority = notificationData.priority === 'critical' ? 1
                     : notificationData.priority === 'high' ? 2
                     : notificationData.priority === 'medium' ? 3
                     : 5;

      // Prepare batch data for queue
      const queueData = createdRecipients.map(rec => ({
        notification_id: notification.id,
        recipient_id: rec.id,
        scheduled_for: scheduledFor,
        priority,
        status: 'queued',
      }));

      // Batch insert all queue items at once
      await tx.notification_queue.createMany({
        data: queueData,
      });

      console.log(`✅ Created ${createdRecipients.length} recipients and queue items in batch`);
      
      return {
        id: notification.id,
        estimatedReach,
        recipientsCreated: createdRecipients.length,
      };
    });

    // If this is an immediate notification, trigger background queue processing (non-blocking)
    if (notificationData.deliveryType === "immediate") {
      // Don't await - let it run in background
      processEmailQueue().catch(err => {
        console.error('Background queue processing error:', err);
      });
    }

    // Return success response
    return {
      success: true,
      data: {
        id: result.id,
        message:
          notificationData.deliveryType === "immediate"
            ? "Notification queued for immediate delivery"
            : "Notification has been scheduled",
        estimatedReach: result.estimatedReach,
        recipientsQueued: result.recipientsCreated || 0,
        queueStatus: "Recipients have been added to the notification queue",
      },
    };
  } catch (error) {
    console.error("Notification creation error:", error);

    // Handle Prisma errors
    if (error.code && error.code.startsWith('P')) {
      throw createError({
        statusCode: 400,
        statusMessage: "Database operation failed",
        data: {
          error: error.message,
          code: error.code
        }
      });
    }

    // Handle known errors with status codes
    if (error.statusCode) {
      throw error;
    }

    // Generic server error
    throw createError({
      statusCode: 500,
      statusMessage: "Failed to create notification",
      data: {
        error: error.message
      }
    });
  } finally {
  }
});

