import { describe, it, expect } from 'vitest';
import {
  createABTest,
  assignVariant,
  calculateMetrics,
  determineWinner,
  generateABTestReport,
  validateABTest,
} from './_core/abTesting.ts';

describe('A/B Testing', () => {
  const testVariants = [
    {
      id: 'variant-a',
      name: 'Subject A',
      subject: 'Limited Time Offer!',
      htmlContent: '<p>Offer A</p>',
      percentage: 50,
    },
    {
      id: 'variant-b',
      name: 'Subject B',
      subject: 'Exclusive Deal Inside',
      htmlContent: '<p>Offer B</p>',
      percentage: 50,
    },
  ];

  it('should create A/B test configuration', () => {
    const config = createABTest({
      campaignId: 1,
      testName: 'Subject Line Test',
      variants: testVariants,
    });

    expect(config.testName).toBe('Subject Line Test');
    expect(config.variants.length).toBe(2);
    expect(config.winnerCriteria).toBe('open_rate');
  });

  it('should validate A/B test configuration', () => {
    const config = createABTest({
      campaignId: 1,
      testName: 'Valid Test',
      variants: testVariants,
    });

    const validation = validateABTest(config);
    expect(validation.valid).toBe(true);
    expect(validation.errors.length).toBe(0);
  });

  it('should reject invalid percentage distribution', () => {
    const invalidVariants = [
      { ...testVariants[0], percentage: 60 },
      { ...testVariants[1], percentage: 30 },
    ];

    expect(() => {
      createABTest({
        campaignId: 1,
        testName: 'Invalid Test',
        variants: invalidVariants,
      });
    }).toThrow('Variant percentages must sum to 100');
  });

  it('should assign variants consistently', () => {
    const recipientId = 'user-123';
    const variant1 = assignVariant(testVariants, recipientId);
    const variant2 = assignVariant(testVariants, recipientId);

    expect(variant1.id).toBe(variant2.id);
  });

  it('should distribute variants across recipients', () => {
    const variants = [
      { id: 'a', name: 'A', subject: 'A', htmlContent: 'A', percentage: 50 },
      { id: 'b', name: 'B', subject: 'B', htmlContent: 'B', percentage: 50 },
    ];

    const assignments: Record<string, number> = { a: 0, b: 0 };

    for (let i = 0; i < 100; i++) {
      const variant = assignVariant(variants, `user-${i}`);
      assignments[variant.id]++;
    }

    // Should roughly split 50/50
    expect(assignments.a).toBeGreaterThan(30);
    expect(assignments.b).toBeGreaterThan(30);
  });

  it('should calculate metrics correctly', () => {
    const metrics = calculateMetrics('variant-a', {
      sent: 1000,
      delivered: 950,
      opened: 380,
      clicked: 95,
      bounced: 50,
      complained: 5,
    });

    expect(metrics.openRate).toBeCloseTo(40, 0); // 380/950 * 100
    expect(metrics.clickRate).toBeCloseTo(10, 0); // 95/950 * 100
    expect(metrics.bounceRate).toBeCloseTo(5, 0); // 50/1000 * 100
  });

  it('should determine winner based on open rate', () => {
    const metrics = [
      {
        variantId: 'variant-a',
        sent: 1000,
        delivered: 950,
        opened: 380,
        clicked: 95,
        bounced: 50,
        complained: 5,
        openRate: 40,
        clickRate: 10,
        bounceRate: 5,
      },
      {
        variantId: 'variant-b',
        sent: 1000,
        delivered: 950,
        opened: 285,
        clicked: 95,
        bounced: 50,
        complained: 5,
        openRate: 30,
        clickRate: 10,
        bounceRate: 5,
      },
    ];

    const winner = determineWinner(metrics, 'open_rate', 100);

    expect(winner).toBeDefined();
    expect(winner?.winnerId).toBe('variant-a');
    expect(winner?.confidence).toBeGreaterThan(0);
  });

  it('should require minimum sample size', () => {
    const metrics = [
      {
        variantId: 'variant-a',
        sent: 10,
        delivered: 10,
        opened: 5,
        clicked: 1,
        bounced: 0,
        complained: 0,
        openRate: 50,
        clickRate: 10,
        bounceRate: 0,
      },
    ];

    const winner = determineWinner(metrics, 'open_rate', 100);

    expect(winner).toBeNull();
  });

  it('should generate A/B test report', () => {
    const config = createABTest({
      campaignId: 1,
      testName: 'Subject Line Test',
      variants: testVariants,
    });

    const metrics = [
      {
        variantId: 'variant-a',
        sent: 1000,
        delivered: 950,
        opened: 380,
        clicked: 95,
        bounced: 50,
        complained: 5,
        openRate: 40,
        clickRate: 10,
        bounceRate: 5,
      },
      {
        variantId: 'variant-b',
        sent: 1000,
        delivered: 950,
        opened: 285,
        clicked: 95,
        bounced: 50,
        complained: 5,
        openRate: 30,
        clickRate: 10,
        bounceRate: 5,
      },
    ];

    const report = generateABTestReport(config, metrics);

    expect(report.testName).toBe('Subject Line Test');
    expect(report.variants.length).toBe(2);
    expect(report.winner).toBeDefined();
    expect(report.recommendation).toContain('Winner');
  });

  it('should handle multiple variants', () => {
    const multiVariants = [
      { id: 'a', name: 'A', subject: 'A', htmlContent: 'A', percentage: 33 },
      { id: 'b', name: 'B', subject: 'B', htmlContent: 'B', percentage: 33 },
      { id: 'c', name: 'C', subject: 'C', htmlContent: 'C', percentage: 34 },
    ];

    const config = createABTest({
      campaignId: 1,
      testName: 'Three-Way Test',
      variants: multiVariants,
    });

    expect(config.variants.length).toBe(3);

    const validation = validateABTest(config);
    expect(validation.valid).toBe(true);
  });
});
