import pool from '../config/database';
import scheduledMessagesService, { ScheduledMessageRule } from '../services/scheduledMessages.service';
import logger from '../utils/logger';

const INTERVAL_MS = 60 * 1000; // 60 seconds
let jobInterval: ReturnType<typeof setInterval> | null = null;
let isRunning = false;

function isDue(rule: ScheduledMessageRule): boolean {
  const now = new Date();
  const today = now.toISOString().slice(0, 10);

  // Skip if already sent today
  if (rule.last_sent_at && rule.last_sent_at.slice(0, 10) === today) {
    return false;
  }

  if (rule.trigger_mode === 'day_of_week') {
    // Check weekday matches
    if (now.getDay() !== rule.day_of_week) return false;

    // Check HH:MM matches (within the 60s window)
    if (!rule.send_time) return false;
    const [ruleHour, ruleMinute] = rule.send_time.split(':').map(Number);
    if (now.getHours() !== ruleHour || now.getMinutes() !== ruleMinute) return false;

    return true;
  }

  if (rule.trigger_mode === 'days_before_month_start') {
    if (rule.days_before_month_start == null) return false;

    // Compute target date: 1st of next month minus N days
    const firstOfNextMonth = new Date(now.getFullYear(), now.getMonth() + 1, 1);
    const targetDate = new Date(firstOfNextMonth.getTime() - rule.days_before_month_start * 86400000);
    const targetStr = targetDate.toISOString().slice(0, 10);

    return today === targetStr;
  }

  // event-triggered rules are not handled by the job
  return false;
}

async function runScheduledMessagesCheck(): Promise<void> {
  if (isRunning) {
    logger.warn('ScheduledMessagesJob: previous run still in progress — skipping');
    return;
  }
  isRunning = true;

  try {
    const result = await pool.query(
      `SELECT * FROM scheduled_message_rules WHERE active = true AND trigger_mode != 'event'`,
    );

    let processed = 0;
    for (const row of result.rows as ScheduledMessageRule[]) {
      if (!isDue(row)) continue;

      try {
        await scheduledMessagesService.buildAndSend(row);
        await pool.query(
          'UPDATE scheduled_message_rules SET last_sent_at = CURRENT_DATE WHERE id = $1',
          [row.id],
        );
        processed++;
        logger.info('ScheduledMessagesJob: sent message', {
          ruleId: row.id,
          name: row.name,
          type: row.message_type,
        });
      } catch (error) {
        logger.error('ScheduledMessagesJob: failed to process rule', {
          ruleId: row.id,
          error: error instanceof Error ? error.message : String(error),
        });
      }
    }

    if (processed > 0) {
      logger.info(`ScheduledMessagesJob: processed ${processed} rules`);
    }

    // Check one-time messages
    await scheduledMessagesService.sendDueOneTimeMessages();
  } catch (error) {
    logger.error('ScheduledMessagesJob: unexpected error', {
      error: error instanceof Error ? error.message : String(error),
    });
  } finally {
    isRunning = false;
  }
}

export function startScheduledMessagesJob(): void {
  if (jobInterval !== null) {
    logger.warn('Scheduled messages job already running — skipping duplicate start');
    return;
  }
  // Run once after short delay, then repeat
  setTimeout(() => runScheduledMessagesCheck(), 30 * 1000);
  jobInterval = setInterval(() => runScheduledMessagesCheck(), INTERVAL_MS);
  logger.info('Scheduled messages job started (every 60 seconds)');
}

export function stopScheduledMessagesJob(): void {
  if (jobInterval !== null) {
    clearInterval(jobInterval);
    jobInterval = null;
  }
  logger.info('Scheduled messages job stopped');
}
