/**
 * Deposit Reminder Service
 *
 * Handles automated deposit reminders for bookings:
 * - Sends reminders 24 hours before scheduled appointments
 * - Only for bookings with unpaid deposits
 * - Supports bilingual email (Arabic/English)
 * - Tracks reminder status in database
 */

import { prisma } from '../db';
import { sendEmailImmediate } from '../email';
import { createDepositReminderEmail } from './email/templates/deposit-reminder-templates';
import { enqueueJob } from '@/lib/queue';
import { logger } from '@/lib/logger';

// Types
export interface BookingForDepositReminder {
  id: string;
  userId: string;
  customerName: string;
  customerEmail: string;
  customerPhone: string;
  service: string;
  appointmentDate: Date | string;
  appointmentTime: string;
  depositAmount: number;
  status: string;
  depositReminderSentAt: Date | null;
  depositReminderCount: number;
}

export interface DepositReminderResult {
  bookingId: string;
  emailSent: boolean;
  error?: string;
}

export interface ProcessDepositRemindersResult {
  processed: number;
  enqueued: number;
  skipped: number;
}

/**
 * Get bookings that are due for 24-hour deposit reminders
 * Finds bookings where:
 * - appointmentDate is within 24-25 hours from now
 * - status is 'pending' or 'confirmed'
 * - depositPaid is false
 * - depositAmount > 0
 * - customerEmail is not null
 * - depositReminderSentAt is null (not yet sent)
 */
export async function getDueDepositReminders(): Promise<BookingForDepositReminder[]> {
  const now = new Date();
  const in24Hours = new Date(now.getTime() + 24 * 60 * 60 * 1000);
  const in25Hours = new Date(now.getTime() + 25 * 60 * 60 * 1000);

  try {
    // Try Prisma first (primary)
    const bookings = await prisma.bookings.findMany({
      where: {
        appointmentDate: {
          gte: in24Hours,
          lt: in25Hours,
        },
        status: {
          in: ['pending', 'confirmed'],
        },
        depositPaid: false,
        depositAmount: {
          gt: 0,
        },
        customerEmail: {
          not: null,
        },
        depositReminderSentAt: null,
      },
      select: {
        id: true,
        userId: true,
        customerName: true,
        customerEmail: true,
        customerPhone: true,
        service: true,
        appointmentDate: true,
        appointmentTime: true,
        depositAmount: true,
        status: true,
        depositReminderSentAt: true,
        depositReminderCount: true,
      },
    });

    return bookings.map((b) => ({
      ...b,
      customerEmail: b.customerEmail!, // Already filtered for not null
      depositAmount: b.depositAmount!, // Already filtered for > 0
      status: b.status as string,
    }));
  } catch (error) {
    const message =
      error instanceof Error ? error.message : 'Unknown error';
    logger.error('Failed to query due deposit reminders', { error: message });
    throw error;
  }
}

/**
 * Generate payment link for a booking
 */
function generatePaymentLink(bookingId: string, language: 'en' | 'ar'): string {
  const baseUrl = process.env.NEXT_PUBLIC_APP_URL || 'https://mawidi.com';
  return `${baseUrl}/${language}/bookings/${bookingId}/pay`;
}

/**
 * Detect language preference based on customer name or default
 */
function detectLanguage(customerName: string): 'en' | 'ar' {
  // Simple heuristic: if name contains Arabic characters, use Arabic
  const arabicPattern = /[\u0600-\u06FF]/;
  return arabicPattern.test(customerName) ? 'ar' : 'en';
}

/**
 * Send deposit reminder email
 */
export async function sendDepositReminderEmail(
  booking: BookingForDepositReminder
): Promise<boolean> {
  if (!booking.customerEmail) {
    logger.debug('Skipping deposit reminder', {
      bookingId: booking.id,
      reason: 'no email',
    });
    return false;
  }

  try {
    // Format appointment date
    const appointmentDate =
      booking.appointmentDate instanceof Date
        ? booking.appointmentDate
        : new Date(booking.appointmentDate);

    const language = detectLanguage(booking.customerName);

    const dateStr = appointmentDate.toLocaleDateString(
      language === 'ar' ? 'ar-SA' : 'en-US',
      {
        weekday: 'long',
        year: 'numeric',
        month: 'long',
        day: 'numeric',
      }
    );

    // Get currency from user's preferences or default to QAR
    const currency = 'QAR'; // Default GCC currency

    const paymentLink = generatePaymentLink(booking.id, language);

    const emailTemplate = createDepositReminderEmail({
      customerName: booking.customerName,
      appointmentDate: dateStr,
      appointmentTime: booking.appointmentTime,
      service: booking.service,
      depositAmount: booking.depositAmount,
      currency,
      paymentLink,
      language,
    });

    const success = await sendEmailImmediate(booking.customerEmail, emailTemplate);

    if (success) {
      logger.info('Deposit reminder email sent', { bookingId: booking.id });
    }

    return success;
  } catch (error) {
    const message = error instanceof Error ? error.message : 'Unknown error';
    logger.error('Failed to send deposit reminder email', {
      bookingId: booking.id,
      error: message,
    });
    return false;
  }
}

/**
 * Update deposit reminder status in database
 */
export async function updateDepositReminderStatus(
  bookingId: string,
  emailSent: boolean,
  error?: string
): Promise<void> {
  const updateData = {
    depositReminderSentAt: new Date(),
    depositReminderCount: { increment: 1 },
    updatedAt: new Date(),
  };

  try {
    // Update via Prisma
    await prisma.bookings.update({
      where: { id: bookingId },
      data: updateData,
    });

    logger.info('Deposit reminder status updated', {
      bookingId,
      emailSent,
      error: error || null,
    });
  } catch (dbError) {
    const message = dbError instanceof Error ? dbError.message : 'Unknown error';
    logger.error('Failed to update deposit reminder status', {
      bookingId,
      error: message,
    });
  }
}

/**
 * Process all due deposit reminders
 * Main function to be called by cron job - enqueues jobs for each booking
 */
export async function processDepositReminders(): Promise<ProcessDepositRemindersResult> {
  const result: ProcessDepositRemindersResult = {
    processed: 0,
    skipped: 0,
    enqueued: 0,
  };

  try {
    const dueBookings = await getDueDepositReminders();
    result.processed = dueBookings.length;

    logger.info('Processing due deposit reminders', { count: dueBookings.length });

    for (const booking of dueBookings) {
      // Skip if cancelled
      if (booking.status === 'cancelled') {
        result.skipped++;
        continue;
      }

      // Skip if no email
      if (!booking.customerEmail) {
        result.skipped++;
        continue;
      }

      await enqueueJob('deposit_reminder', { bookingId: booking.id });
      result.enqueued++;
    }

    logger.info('Deposit reminder enqueue complete', {
      enqueued: result.enqueued,
      skipped: result.skipped,
    });

    return result;
  } catch (error) {
    const message = error instanceof Error ? error.message : 'Unknown error';
    logger.error('Error processing deposit reminders', { error: message });
    throw error;
  }
}

/**
 * Send deposit reminder for a specific booking
 * Called by the job worker when processing enqueued jobs
 */
export async function sendDepositReminderForBooking(
  bookingId: string
): Promise<DepositReminderResult> {
  try {
    // Fetch the booking
    const booking = await prisma.bookings.findUnique({
      where: { id: bookingId },
      select: {
        id: true,
        userId: true,
        customerName: true,
        customerEmail: true,
        customerPhone: true,
        service: true,
        appointmentDate: true,
        appointmentTime: true,
        depositAmount: true,
        depositPaid: true,
        status: true,
        depositReminderSentAt: true,
        depositReminderCount: true,
      },
    });

    if (!booking) {
      return {
        bookingId,
        emailSent: false,
        error: 'Booking not found',
      };
    }

    // Check if deposit has already been paid (race condition protection)
    if (booking.depositPaid) {
      logger.info('Deposit already paid, skipping reminder', { bookingId });
      return {
        bookingId,
        emailSent: false,
        error: 'Deposit already paid',
      };
    }

    if (!booking.customerEmail) {
      return {
        bookingId,
        emailSent: false,
        error: 'No customer email available',
      };
    }

    if (!booking.depositAmount || booking.depositAmount <= 0) {
      return {
        bookingId,
        emailSent: false,
        error: 'No deposit amount configured',
      };
    }

    const bookingData: BookingForDepositReminder = {
      ...booking,
      customerEmail: booking.customerEmail,
      depositAmount: booking.depositAmount,
      status: booking.status as string,
    };

    // Send reminder email
    const emailSent = await sendDepositReminderEmail(bookingData);

    // Update status (even if failed, to prevent retry loops)
    const errorMsg = !emailSent ? 'Email send failed' : undefined;
    await updateDepositReminderStatus(bookingId, emailSent, errorMsg);

    return {
      bookingId,
      emailSent,
      error: errorMsg,
    };
  } catch (error) {
    const errorMsg = error instanceof Error ? error.message : 'Unknown error';
    logger.error('Failed to send deposit reminder', { bookingId, error: errorMsg });

    // Update status to prevent retry loops
    await updateDepositReminderStatus(bookingId, false, errorMsg);

    return {
      bookingId,
      emailSent: false,
      error: errorMsg,
    };
  }
}
