import { WEBHOOK_CONFIG } from './config/constants';
import { systemSettingsService } from './services/system-settings.service';

// Webhook configuration factory (allows testing with env var overrides)
async function getWebhookConfig() {
  const authToken = await systemSettingsService.getN8NWebhookToken();
  return {
    url: process.env.N8N_WEBHOOK_URL || '',
    authToken: authToken || '',
    maxRetries: WEBHOOK_CONFIG.MAX_RETRIES,
    timeoutMs: WEBHOOK_CONFIG.TIMEOUT_MS,
    retryDelays: [...WEBHOOK_CONFIG.RETRY_DELAYS_MS],
  };
}

export interface DemoBookingWebhookPayload {
  event: 'demo_booking_created';
  timestamp: string;
  booking: {
    id: string;
    fullName: string;
    email: string;
    telephone: string;
    date: string;
    time: string;
    duration: string;
    specialRequirements: string | null;
    language: string;
    status: string;
  };
}

interface WebhookResult {
  success: boolean;
  attemptCount: number;
  response?: string;
  error?: string;
}

/**
 * Send demo booking data to n8n webhook with retry logic
 * Non-blocking: logs errors but doesn't throw
 */
export async function sendDemoBookingWebhook(
  bookingId: string,
  bookingData: Omit<DemoBookingWebhookPayload['booking'], 'id'>
): Promise<WebhookResult> {
  const WEBHOOK_CONFIG = await getWebhookConfig();

  // Validate webhook configuration
  if (!WEBHOOK_CONFIG.url || !WEBHOOK_CONFIG.authToken) {
    console.error('Webhook configuration missing: N8N_WEBHOOK_URL or n8n.webhook_auth_token not set');
    return {
      success: false,
      attemptCount: 0,
      error: 'Webhook configuration missing',
    };
  }

  const payload: DemoBookingWebhookPayload = {
    event: 'demo_booking_created',
    timestamp: new Date().toISOString(),
    booking: {
      id: bookingId,
      ...bookingData,
    },
  };

  let lastError: string | undefined;
  let attemptCount = 0;

  // Retry loop with exponential backoff
  for (let attempt = 0; attempt < WEBHOOK_CONFIG.maxRetries; attempt++) {
    attemptCount = attempt + 1;

    try {
      // Add delay before retry attempts
      if (attempt > 0) {
        await new Promise(resolve => setTimeout(resolve, WEBHOOK_CONFIG.retryDelays[attempt - 1]));
      }

      // Send webhook with timeout
      const controller = new AbortController();
      const timeoutId = setTimeout(() => controller.abort(), WEBHOOK_CONFIG.timeoutMs);

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

      clearTimeout(timeoutId);

      // Check response status
      if (response.ok) {
        const responseText = await response.text();

        // Update database with success
        await updateWebhookStatus(bookingId, 'sent', attemptCount, responseText);

        console.log(`Webhook sent successfully for booking ${bookingId} on attempt ${attemptCount}`);

        return {
          success: true,
          attemptCount,
          response: responseText,
        };
      } else {
        lastError = `HTTP ${response.status}: ${response.statusText}`;
        console.error(`Webhook attempt ${attemptCount} failed for booking ${bookingId}: ${lastError}`);
      }
    } catch (error) {
      if (error instanceof Error) {
        if (error.name === 'AbortError') {
          lastError = 'Request timeout';
        } else {
          lastError = error.message;
        }
      } else {
        lastError = 'Unknown error';
      }

      console.error(`Webhook attempt ${attemptCount} failed for booking ${bookingId}:`, error);
    }
  }

  // All retries exhausted - update database with failure
  await updateWebhookStatus(bookingId, 'failed', attemptCount, lastError);

  console.error(`Webhook failed for booking ${bookingId} after ${attemptCount} attempts: ${lastError}`);

  return {
    success: false,
    attemptCount,
    error: lastError,
  };
}

/**
 * Update webhook status in Supabase database
 */
async function updateWebhookStatus(
  bookingId: string,
  status: 'pending' | 'sent' | 'failed',
  retryCount: number,
  response?: string
): Promise<void> {
  try {

    if (error) {
      console.error(`Failed to update webhook status for booking ${bookingId}:`, error);
    }
  } catch (error) {
    console.error(`Failed to update webhook status for booking ${bookingId}:`, error);
    // Don't throw - this is non-critical
  }
}

/**
 * Retry failed webhooks (can be called by cron job or background task)
 */
export async function retryFailedWebhooks(maxAge: number = 24 * 60 * 60 * 1000): Promise<number> {

  const WEBHOOK_CONFIG = getWebhookConfig();
  const cutoffDate = new Date(Date.now() - maxAge);

  // Find failed webhooks within the time window

  if (error || !failedBookings) {
    console.error('Failed to fetch failed webhooks:', error);
    return 0;
  }

  let retriedCount = 0;

  for (const booking of failedBookings) {
    const result = await sendDemoBookingWebhook(booking.id, {
      fullName: booking.full_name,
      email: booking.email,
      telephone: booking.telephone,
      date: booking.appointment_date.split('T')[0],
      time: booking.appointment_time,
      duration: booking.duration,
      specialRequirements: booking.special_requirements,
      language: booking.language,
      status: booking.status,
    });

    if (result.success) {
      retriedCount++;
    }
  }

  return retriedCount;
}
