import { describe, it, expect, beforeEach, vi } from 'vitest';
import { alertDeliveryService } from './alertDeliveryService.ts';
import { AlertLog, AlertTemplate } from '../db.alerts.schema.ts';

describe('alertDeliveryService', () => {
  let mockAlert: AlertLog;
  let mockTemplate: AlertTemplate;

  beforeEach(() => {
    mockAlert = {
      id: 'alert-001',
      alertType: 'latency_critical',
      severity: 'critical',
      message: 'WebSocket latency exceeded 500ms',
      status: 'active',
      team: 'ops',
      escalationCount: 0,
      acknowledgedAt: undefined,
      resolvedAt: undefined,
      createdAt: Date.now(),
      updatedAt: Date.now(),
    } as AlertLog;

    mockTemplate = {
      id: 'template-001',
      alertType: 'latency_critical',
      title: 'Critical Latency Alert',
      description: 'WebSocket latency exceeded threshold',
      slackTemplate: '🚨 *Critical Latency Alert*\nLatency: {{severity}}',
      emailTemplate: '<h2>Critical Latency Alert</h2><p>{{message}}</p>',
      pagerdutyTemplate: 'Critical Latency: {{severity}}',
      variables: '["severity","message"]',
      severity: 'critical',
      enabled: 1,
      createdAt: Date.now(),
      updatedAt: Date.now(),
    } as AlertTemplate;

    // Mock environment variables
    process.env.SLACK_WEBHOOK_URL = 'https://hooks.slack.com/services/test';
    process.env.PAGERDUTY_INTEGRATION_KEY = 'test-key';
    process.env.ALERT_EMAIL_RECIPIENTS = 'admin@example.com';
    process.env.BREVO_API_KEY = 'test-api-key';
  });

  describe('sendAlert', () => {
    it('should send alert through all channels', async () => {
      const results = await alertDeliveryService.sendAlert(mockAlert, mockTemplate);

      expect(results).toHaveLength(3);
      expect(results.map((r) => r.channel)).toEqual(['slack', 'pagerduty', 'email']);
    });

    it('should handle missing environment variables', async () => {
      delete process.env.SLACK_WEBHOOK_URL;

      const results = await alertDeliveryService.sendAlert(mockAlert, mockTemplate);
      const slackResult = results.find((r) => r.channel === 'slack');

      expect(slackResult?.success).toBe(false);
      expect(slackResult?.error).toContain('SLACK_WEBHOOK_URL');
    });
  });

  describe('sendToSlack', () => {
    it('should return success when webhook URL is configured', async () => {
      const result = await alertDeliveryService.sendToSlack(mockAlert, mockTemplate);

      expect(result.channel).toBe('slack');
      expect(result.message).toBeDefined();
      // Result depends on network call to mock URL
    });

    it('should return error when webhook URL is missing', async () => {
      delete process.env.SLACK_WEBHOOK_URL;

      const result = await alertDeliveryService.sendToSlack(mockAlert, mockTemplate);

      expect(result.success).toBe(false);
      expect(result.error).toContain('SLACK_WEBHOOK_URL');
    });

    it('should render template variables', async () => {
      const result = await alertDeliveryService.sendToSlack(mockAlert, mockTemplate);

      expect(result.channel).toBe('slack');
      expect(result.message).toBeDefined();
    });
  });

  describe('sendToPagerDuty', () => {
    it('should return success when integration key is configured', async () => {
      const result = await alertDeliveryService.sendToPagerDuty(mockAlert, mockTemplate);

      expect(result.channel).toBe('pagerduty');
      expect(result.message).toBeDefined();
      // Result depends on network call to mock key
    });

    it('should return error when integration key is missing', async () => {
      delete process.env.PAGERDUTY_INTEGRATION_KEY;

      const result = await alertDeliveryService.sendToPagerDuty(mockAlert, mockTemplate);

      expect(result.success).toBe(false);
      expect(result.error).toContain('PAGERDUTY_INTEGRATION_KEY');
    });

    it('should map alert severity to PagerDuty severity', async () => {
      const criticalAlert = { ...mockAlert, severity: 'critical' as const };
      const result = await alertDeliveryService.sendToPagerDuty(criticalAlert, mockTemplate);

      expect(result.channel).toBe('pagerduty');
    });
  });

  describe('sendToEmail', () => {
    it('should return success when email recipients configured', async () => {
      const result = await alertDeliveryService.sendToEmail(mockAlert, mockTemplate);

      expect(result.channel).toBe('email');
      expect(result.message).toBeDefined();
      // Result depends on network call to Brevo API
    });

    it('should return error when email recipients missing', async () => {
      delete process.env.ALERT_EMAIL_RECIPIENTS;

      const result = await alertDeliveryService.sendToEmail(mockAlert, mockTemplate);

      expect(result.success).toBe(false);
      expect(result.error).toContain('ALERT_EMAIL_RECIPIENTS');
    });

    it('should return error when Brevo API key missing', async () => {
      delete process.env.BREVO_API_KEY;

      const result = await alertDeliveryService.sendToEmail(mockAlert, mockTemplate);

      expect(result.success).toBe(false);
      expect(result.error).toContain('BREVO_API_KEY');
    });

    it('should parse multiple email recipients', async () => {
      process.env.ALERT_EMAIL_RECIPIENTS = 'admin@example.com, ops@example.com, support@example.com';

      const result = await alertDeliveryService.sendToEmail(mockAlert, mockTemplate);

      expect(result.channel).toBe('email');
      expect(result.message).toBeDefined();
      // Should handle comma-separated recipients
    });
  });

  describe('retryFailedDeliveries', () => {
    it('should return retry statistics', async () => {
      const stats = await alertDeliveryService.retryFailedDeliveries();

      expect(stats).toHaveProperty('retried');
      expect(stats).toHaveProperty('successful');
      expect(typeof stats.retried).toBe('number');
      expect(typeof stats.successful).toBe('number');
    });
  });

  describe('getDeliveryStats', () => {
    it('should return delivery statistics', () => {
      const stats = alertDeliveryService.getDeliveryStats();

      expect(stats).toHaveProperty('totalSent');
      expect(stats).toHaveProperty('successRate');
      expect(stats).toHaveProperty('byChannel');
      expect(stats.successRate).toBeGreaterThanOrEqual(0);
      expect(stats.successRate).toBeLessThanOrEqual(1);
    });

    it('should have stats for all channels', () => {
      const stats = alertDeliveryService.getDeliveryStats();

      expect(stats.byChannel).toHaveProperty('slack');
      expect(stats.byChannel).toHaveProperty('email');
      expect(stats.byChannel).toHaveProperty('pagerduty');
    });

    it('should have valid channel statistics', () => {
      const stats = alertDeliveryService.getDeliveryStats();

      Object.values(stats.byChannel).forEach((channel) => {
        expect(channel.sent).toBeGreaterThanOrEqual(0);
        expect(channel.success).toBeGreaterThanOrEqual(0);
        expect(channel.success).toBeLessThanOrEqual(channel.sent);
      });
    });
  });
});
