/**
 * Demo Booking Reminder Service
 *
 * Handles automated reminders for demo bookings:
 * - Sends reminders 24 hours before scheduled appointments
 * - Supports both Email and WhatsApp (via n8n webhook)
 * - Tracks reminder status in database
 */

import { prisma } from '../db';
import { sendDemoReminderEmail } from '../email';
import { WEBHOOK_CONFIG } from '../config/constants';
import { systemSettingsService } from './system-settings.service';

// Types
export interface DemoBookingForReminder {
  id: string;
  fullName: string;
  email: string;
  telephone: string;
  appointmentDate: Date | string;
  appointmentTime: string;
  duration: string;
  language: string;
  status: string;
  googleJoinUrl: string | null;
  customerTimezone: string | null;
  reminderStatus: string | null;
  reminderSentAt: Date | null;
}

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

export interface ProcessRemindersResult {
  processed: number;
  sent: number;
  failed: number;
  skipped: number;
  results: ReminderResult[];
}

// Webhook configuration
async function getWebhookConfig() {
  const authToken = await systemSettingsService.getN8NWebhookToken();
  return {
    url: process.env.N8N_WEBHOOK_URL || '',
    authToken: authToken || '',
    timeoutMs: WEBHOOK_CONFIG.TIMEOUT_MS,
  };
}

/**
 * Get bookings that are due for 24-hour reminders
 * Finds bookings where:
 * - appointmentDate is within 24-25 hours from now
 * - status is 'pending' or 'confirmed'
 * - reminderSentAt is null (not yet sent)
 * - Has a Google Meet link (googleJoinUrl)
 */
export async function getDueReminders(): Promise<DemoBookingForReminder[]> {
  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.demo_bookings.findMany({
      where: {
        appointmentDate: {
          gte: in24Hours,
          lt: in25Hours,
        },
        status: {
          in: ['pending', 'confirmed'],
        },
        reminderSentAt: null,
        googleJoinUrl: {
          not: null,
        },
      },
      select: {
        id: true,
        fullName: true,
        email: true,
        telephone: true,
        appointmentDate: true,
        appointmentTime: true,
        duration: true,
        language: true,
        status: true,
        googleJoinUrl: true,
        customerTimezone: true,
        reminderStatus: true,
        reminderSentAt: true,
      },
    });

    return bookings.map((b) => ({
      ...b,
      status: b.status as string,
      reminderStatus: b.reminderStatus as string | null,
    }));
  } catch (error) {
    console.error('Failed to query due reminders:', error);
    throw error;
  }
}

/**
 * Send email reminder with meeting link
 */
export async function sendEmailReminder(
  booking: DemoBookingForReminder
): Promise<boolean> {
  if (!booking.googleJoinUrl) {
    console.log(`Skipping email reminder for ${booking.id}: no meeting link`);
    return false;
  }

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

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

    const success = await sendDemoReminderEmail(
      booking.email,
      booking.fullName,
      dateStr,
      booking.appointmentTime,
      booking.duration,
      booking.googleJoinUrl,
      booking.language as 'en' | 'ar'
    );

    if (success) {
      console.log(`Email reminder sent for booking ${booking.id}`);
    }

    return success;
  } catch (error) {
    console.error(`Failed to send email reminder for ${booking.id}:`, error);
    return false;
  }
}

/**
 * Send WhatsApp reminder via n8n webhook
 */
export async function sendWhatsAppReminder(
  booking: DemoBookingForReminder
): Promise<boolean> {
  const config = await getWebhookConfig();

  if (!config.url || !config.authToken) {
    console.log(
      `Skipping WhatsApp reminder for ${booking.id}: webhook not configured`
    );
    return false;
  }

  if (!booking.telephone) {
    console.log(
      `Skipping WhatsApp reminder for ${booking.id}: no phone number`
    );
    return false;
  }

  if (!booking.googleJoinUrl) {
    console.log(
      `Skipping WhatsApp reminder for ${booking.id}: no meeting link`
    );
    return false;
  }

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

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

    const payload = {
      event: 'demo_reminder_24h',
      timestamp: new Date().toISOString(),
      booking: {
        id: booking.id,
        fullName: booking.fullName,
        telephone: booking.telephone,
        email: booking.email,
        date: dateStr,
        time: booking.appointmentTime,
        duration: booking.duration,
        meetingLink: booking.googleJoinUrl,
        language: booking.language,
        timezone: booking.customerTimezone || 'Asia/Qatar',
      },
    };

    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), config.timeoutMs);

    const response = await fetch(config.url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${config.authToken}`,
      },
      body: JSON.stringify(payload),
      signal: controller.signal,
    });

    clearTimeout(timeoutId);

    if (response.ok) {
      console.log(`WhatsApp reminder webhook sent for booking ${booking.id}`);
      return true;
    } else {
      console.error(
        `WhatsApp reminder webhook failed for ${booking.id}: HTTP ${response.status}`
      );
      return false;
    }
  } catch (error) {
    console.error(
      `Failed to send WhatsApp reminder webhook for ${booking.id}:`,
      error
    );
    return false;
  }
}

/**
 * Update reminder status in database
 */
export async function updateReminderStatus(
  bookingId: string,
  emailSent: boolean,
  whatsAppSent: boolean,
  error?: string
): Promise<void> {
  // Determine overall status
  let status: string;
  if (emailSent && whatsAppSent) {
    status = 'sent';
  } else if (emailSent || whatsAppSent) {
    status = 'partial';
  } else {
    status = 'failed';
  }

  const updateData = {
    reminderSentAt: new Date(),
    reminderStatus: status,
    reminderEmailSent: emailSent,
    reminderWhatsAppSent: whatsAppSent,
    reminderError: error?.substring(0, 500) || null,
    updatedAt: new Date(),
  };

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

    console.log(`Reminder status updated for booking ${bookingId}: ${status}`);
  } catch (dbError) {
    console.error(
      `Failed to update reminder status for ${bookingId}:`,
      dbError
    );
  }
}

/**
 * Process all due reminders
 * Main function to be called by cron job
 */
export async function processReminders(): Promise<ProcessRemindersResult> {
  const result: ProcessRemindersResult = {
    processed: 0,
    sent: 0,
    failed: 0,
    skipped: 0,
    results: [],
  };

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

    console.log(`Processing ${dueBookings.length} due reminders`);

    for (const booking of dueBookings) {
      // Skip if cancelled
      if (booking.status === 'cancelled') {
        await updateReminderStatus(booking.id, false, false, 'Booking cancelled');
        result.skipped++;
        result.results.push({
          bookingId: booking.id,
          emailSent: false,
          whatsAppSent: false,
          error: 'Booking cancelled',
        });
        continue;
      }

      // Skip if no meeting link
      if (!booking.googleJoinUrl) {
        await updateReminderStatus(
          booking.id,
          false,
          false,
          'No meeting link available'
        );
        result.skipped++;
        result.results.push({
          bookingId: booking.id,
          emailSent: false,
          whatsAppSent: false,
          error: 'No meeting link',
        });
        continue;
      }

      // Send both reminders
      const emailSent = await sendEmailReminder(booking);
      const whatsAppSent = await sendWhatsAppReminder(booking);

      // Update status
      const error =
        !emailSent && !whatsAppSent ? 'Both channels failed' : undefined;
      await updateReminderStatus(booking.id, emailSent, whatsAppSent, error);

      if (emailSent || whatsAppSent) {
        result.sent++;
      } else {
        result.failed++;
      }

      result.results.push({
        bookingId: booking.id,
        emailSent,
        whatsAppSent,
        error,
      });
    }

    console.log(
      `Reminder processing complete: ${result.sent} sent, ${result.failed} failed, ${result.skipped} skipped`
    );

    return result;
  } catch (error) {
    console.error('Error processing reminders:', error);
    throw error;
  }
}

/**
 * Send reminder for a specific booking (manual trigger)
 */
export async function sendReminderForBooking(
  bookingId: string
): Promise<ReminderResult> {
  try {
    // Fetch the booking
    const booking = await prisma.demo_bookings.findUnique({
      where: { id: bookingId },
      select: {
        id: true,
        fullName: true,
        email: true,
        telephone: true,
        appointmentDate: true,
        appointmentTime: true,
        duration: true,
        language: true,
        status: true,
        googleJoinUrl: true,
        customerTimezone: true,
        reminderStatus: true,
        reminderSentAt: true,
      },
    });

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

    if (!booking.googleJoinUrl) {
      return {
        bookingId,
        emailSent: false,
        whatsAppSent: false,
        error: 'No meeting link available',
      };
    }

    const bookingData: DemoBookingForReminder = {
      ...booking,
      status: booking.status as string,
      reminderStatus: booking.reminderStatus as string | null,
    };

    // Send reminders
    const emailSent = await sendEmailReminder(bookingData);
    const whatsAppSent = await sendWhatsAppReminder(bookingData);

    // Update status
    const error =
      !emailSent && !whatsAppSent ? 'Both channels failed' : undefined;
    await updateReminderStatus(bookingId, emailSent, whatsAppSent, error);

    return {
      bookingId,
      emailSent,
      whatsAppSent,
      error,
    };
  } catch (error) {
    const errorMsg =
      error instanceof Error ? error.message : 'Unknown error';
    console.error(`Failed to send reminder for ${bookingId}:`, error);
    return {
      bookingId,
      emailSent: false,
      whatsAppSent: false,
      error: errorMsg,
    };
  }
}
