import { describe, it, expect } from 'vitest';
import {
  validateEmail,
  parseCSVEmailList,
  generateCSVEmailList,
  filterBySegment,
  filterActiveSubscribers,
  deduplicateEmailList,
  mergeEmailLists,
  getListStatistics,
  addTagsToSubscribers,
  removeTagsFromSubscribers,
  updateSubscriberSegment,
  unsubscribeSubscribers,
  type EmailSubscriber,
} from './_core/emailListManagement.ts';

describe('Email List Management', () => {
  const mockSubscribers: EmailSubscriber[] = [
    {
      email: 'john@example.com',
      firstName: 'John',
      lastName: 'Doe',
      segment: 'vip',
      subscribed: true,
      bounced: false,
      complained: false,
      tags: ['premium', 'active'],
      subscribedAt: new Date('2024-01-01'),
    },
    {
      email: 'jane@example.com',
      firstName: 'Jane',
      lastName: 'Smith',
      segment: 'new',
      subscribed: true,
      bounced: false,
      complained: false,
      tags: ['new-user'],
      subscribedAt: new Date('2024-03-01'),
    },
    {
      email: 'bob@example.com',
      firstName: 'Bob',
      lastName: 'Johnson',
      segment: 'inactive',
      subscribed: false,
      bounced: true,
      complained: false,
      tags: [],
      subscribedAt: new Date('2023-01-01'),
    },
  ];

  it('should validate email addresses', () => {
    expect(validateEmail('valid@example.com')).toBe(true);
    expect(validateEmail('another.valid@test.co.uk')).toBe(true);
    expect(validateEmail('invalid-email')).toBe(false);
    expect(validateEmail('missing@domain')).toBe(false);
  });

  it('should parse CSV email list', () => {
    const csv = `email,firstName,lastName,segment,subscribed,bounced,complained
john@example.com,John,Doe,vip,true,false,false
jane@example.com,Jane,Smith,new,true,false,false`;

    const { subscribers, errors } = parseCSVEmailList(csv);

    expect(subscribers.length).toBe(2);
    expect(errors.length).toBe(0);
    expect(subscribers[0].email).toBe('john@example.com');
    expect(subscribers[0].firstName).toBe('John');
  });

  it('should handle invalid emails in CSV', () => {
    const csv = `email,firstName,lastName
john@example.com,John,Doe
invalid-email,Invalid,Email`;

    const { subscribers, errors } = parseCSVEmailList(csv);

    expect(subscribers.length).toBe(1);
    expect(errors.length).toBeGreaterThan(0);
  });

  it('should generate CSV from email list', () => {
    const csv = generateCSVEmailList(mockSubscribers);

    expect(csv).toContain('john@example.com');
    expect(csv).toContain('jane@example.com');
    expect(csv).toContain('vip');
    expect(csv).toContain('new');
  });

  it('should filter subscribers by segment', () => {
    const vipSubscribers = filterBySegment(mockSubscribers, 'vip');
    expect(vipSubscribers.length).toBe(1);
    expect(vipSubscribers[0].email).toBe('john@example.com');

    const allSubscribers = filterBySegment(mockSubscribers, 'all');
    expect(allSubscribers.length).toBe(mockSubscribers.length);
  });

  it('should filter active subscribers', () => {
    const active = filterActiveSubscribers(mockSubscribers);

    expect(active.length).toBe(2);
    expect(active.every((s) => s.subscribed && !s.bounced && !s.complained)).toBe(true);
  });

  it('should deduplicate email list', () => {
    const duplicates: EmailSubscriber[] = [
      ...mockSubscribers,
      { ...mockSubscribers[0], firstName: 'John2' },
    ];

    const { unique, duplicates: foundDuplicates } = deduplicateEmailList(duplicates);

    expect(unique.length).toBe(3);
    expect(foundDuplicates.length).toBe(1);
    expect(foundDuplicates[0]).toBe('john@example.com');
  });

  it('should merge email lists', () => {
    const list1 = mockSubscribers.slice(0, 2);
    const list2 = mockSubscribers.slice(1);

    const merged = mergeEmailLists(list1, list2);

    expect(merged.length).toBe(3);
    expect(merged.every((s) => list1.concat(list2).some((s2) => s2.email === s.email))).toBe(true);
  });

  it('should calculate list statistics', () => {
    const stats = getListStatistics(mockSubscribers);

    expect(stats.total).toBe(3);
    expect(stats.subscribed).toBe(2);
    expect(stats.unsubscribed).toBe(1);
    expect(stats.bounced).toBe(1);
    expect(stats.active).toBe(2);
    expect(stats.bySegment.vip).toBe(1);
    expect(stats.bySegment.new).toBe(1);
  });

  it('should add tags to subscribers', () => {
    const updated = addTagsToSubscribers(mockSubscribers, ['important']);

    expect(updated[0].tags).toContain('important');
    expect(updated[0].tags).toContain('premium');
  });

  it('should remove tags from subscribers', () => {
    const updated = removeTagsFromSubscribers(mockSubscribers, ['premium']);

    expect(updated[0].tags).not.toContain('premium');
    expect(updated[0].tags).toContain('active');
  });

  it('should update subscriber segment', () => {
    const updated = updateSubscriberSegment(
      mockSubscribers,
      ['john@example.com'],
      'high-value'
    );

    expect(updated[0].segment).toBe('high-value');
    expect(updated[1].segment).toBe('new');
  });

  it('should unsubscribe subscribers', () => {
    const updated = unsubscribeSubscribers(mockSubscribers, ['john@example.com']);

    expect(updated[0].subscribed).toBe(false);
    expect(updated[0].unsubscribedAt).toBeDefined();
    expect(updated[1].subscribed).toBe(true);
  });

  it('should handle case-insensitive email matching', () => {
    const updated = updateSubscriberSegment(
      mockSubscribers,
      ['JOHN@EXAMPLE.COM'],
      'high-value'
    );

    expect(updated[0].segment).toBe('high-value');
  });
});
