import { prisma } from '../config/database';
import { logger } from '../utils/logger';
import { smsQueueService } from './sms-queue.service';

class SmsNotificationService {
  /**
   * Send a shift reminder SMS.
   * Respects smsShiftReminders setting and calculates appropriate delay.
   */
  async sendShiftReminder(
    phone: string,
    data: { name: string; shiftTitle: string; shiftTime: string; shiftLocation: string },
    shiftDatetime: Date,
  ): Promise<void> {
    if (!(await this.shouldSend(phone))) return;

    const settings = await this.getSettings();
    if (!settings.smsShiftReminders) return;

    const template = await this.getTemplate('shift-reminder');
    if (!template) return;

    const message = this.substituteTemplate(template, {
      name: data.name,
      shiftTitle: data.shiftTitle,
      shiftTime: data.shiftTime,
      shiftLocation: data.shiftLocation,
    });

    // Calculate delay: send N hours before the shift
    const reminderHours = settings.smsShiftReminderHours || 24;
    const sendAt = new Date(shiftDatetime.getTime() - reminderHours * 60 * 60 * 1000);
    const delayMs = Math.max(0, sendAt.getTime() - Date.now());

    await smsQueueService.addSmsJob(
      { recipientId: '', campaignId: '', phone, message, attemptNumber: 1 },
      delayMs,
    );
  }

  /**
   * Send a shift signup confirmation SMS. Sent immediately.
   */
  async sendShiftSignupConfirmation(
    phone: string,
    data: { name: string; shiftTitle: string; shiftDate: string; shiftTime: string },
  ): Promise<void> {
    if (!(await this.shouldSend(phone))) return;

    const settings = await this.getSettings();
    if (!settings.smsShiftSignupConfirm) return;

    const template = await this.getTemplate('shift-signup-confirm');
    if (!template) return;

    const message = this.substituteTemplate(template, {
      name: data.name,
      shiftTitle: data.shiftTitle,
      shiftDate: data.shiftDate,
      shiftTime: data.shiftTime,
    });

    await smsQueueService.addSmsJob(
      { recipientId: '', campaignId: '', phone, message, attemptNumber: 1 },
    );
  }

  /**
   * Send a welcome SMS to a new volunteer. Sent immediately.
   */
  async sendVolunteerWelcome(
    phone: string,
    data: { name: string },
  ): Promise<void> {
    if (!(await this.shouldSend(phone))) return;

    const settings = await this.getSettings();
    if (!settings.smsVolunteerWelcome) return;

    const template = await this.getTemplate('volunteer-welcome');
    if (!template) return;

    const message = this.substituteTemplate(template, { name: data.name });

    await smsQueueService.addSmsJob(
      { recipientId: '', campaignId: '', phone, message, attemptNumber: 1 },
    );
  }

  /**
   * Send a custom one-off SMS notification. Sent immediately.
   */
  async sendCustom(phone: string, message: string): Promise<void> {
    if (!(await this.shouldSend(phone))) return;

    await smsQueueService.addSmsJob(
      { recipientId: '', campaignId: '', phone, message, attemptNumber: 1 },
    );
  }

  // ---------------------------------------------------------------------------
  // Private helpers
  // ---------------------------------------------------------------------------

  /**
   * Check whether we should actually send an SMS to this phone.
   * Verifies: enableSms is on, phone is non-empty, phone is not opted out.
   */
  private async shouldSend(phone: string): Promise<boolean> {
    if (!phone || !phone.trim()) return false;

    const settings = await this.getSettings();
    if (!settings.enableSms) return false;

    // Check for opt-out: if a conversation exists with status OPTED_OUT, skip
    const optedOut = await prisma.smsConversation.findFirst({
      where: { phone, status: 'OPTED_OUT' },
      select: { id: true },
    });
    if (optedOut) {
      logger.debug(`SMS notification skipped for ${phone}: opted out`);
      return false;
    }

    return true;
  }

  /**
   * Look up an SmsMessageTemplate by name.
   */
  private async getTemplate(name: string): Promise<string | null> {
    const tmpl = await prisma.smsMessageTemplate.findFirst({
      where: { name },
      select: { template: true },
    });
    return tmpl?.template || null;
  }

  /**
   * Replace {var} placeholders in a template string.
   */
  private substituteTemplate(template: string, vars: Record<string, string>): string {
    return template.replace(/\{(\w+)\}/g, (match, key) => {
      return vars[key] !== undefined ? vars[key] : match;
    });
  }

  /**
   * Fetch site settings (cached per-request is fine for notification context).
   */
  private async getSettings() {
    const { siteSettingsService } = await import('../modules/settings/settings.service');
    return siteSettingsService.get();
  }
}

export const smsNotificationService = new SmsNotificationService();
