/**
 * Tests for tracking system
 */

import {
  addTrackingEntry,
  getAllEntries,
  getTrackingSummary,
  clearTracking,
  exportAsCSV
} from '../src/tracking/tracker';

// Mock chrome storage
const mockStorage: { [key: string]: any } = {};

// Setup chrome storage mocks
(chrome.storage.local.get as jest.Mock).mockImplementation((key) => {
  return Promise.resolve({ [key]: mockStorage[key] });
});

(chrome.storage.local.set as jest.Mock).mockImplementation((data) => {
  Object.assign(mockStorage, data);
  return Promise.resolve();
});

(chrome.storage.local.remove as jest.Mock).mockImplementation((key) => {
  delete mockStorage[key];
  return Promise.resolve();
});

describe('Tracking system', () => {
  beforeEach(() => {
    // Clear mock storage
    Object.keys(mockStorage).forEach((key) => delete mockStorage[key]);
    jest.clearAllMocks();
  });

  test('should add tracking entry', async () => {
    await addTrackingEntry({
      timestamp: Date.now(),
      sourceDomain: 'example.com',
      destinationUrl: 'https://api.binect.de/upload',
      pdfSize: 1024,
      result: 'success'
    });

    const entries = await getAllEntries();
    expect(entries.length).toBe(1);
    expect(entries[0].sourceDomain).toBe('example.com');
    expect(entries[0].result).toBe('success');
  });

  test('should maintain max entries limit', async () => {
    // Add 501 entries
    for (let i = 0; i < 501; i++) {
      await addTrackingEntry({
        timestamp: Date.now(),
        sourceDomain: `example${i}.com`,
        destinationUrl: 'https://api.binect.de/upload',
        pdfSize: 1024,
        result: 'success'
      });
    }

    const entries = await getAllEntries();
    expect(entries.length).toBe(500); // Should be capped at 500
    expect(entries[0].sourceDomain).toBe('example500.com'); // Most recent first
  });

  test('should calculate tracking summary correctly', async () => {
    await addTrackingEntry({
      timestamp: Date.now(),
      sourceDomain: 'example.com',
      destinationUrl: 'https://api.binect.de/upload',
      pdfSize: 1024,
      result: 'success'
    });

    await addTrackingEntry({
      timestamp: Date.now(),
      sourceDomain: 'example2.com',
      destinationUrl: 'https://api.binect.de/upload',
      pdfSize: 2048,
      result: 'failure',
      errorMessage: 'Network error'
    });

    const summary = await getTrackingSummary();
    expect(summary.totalTransfers).toBe(2);
    expect(summary.successfulTransfers).toBe(1);
    expect(summary.failedTransfers).toBe(1);
    expect(summary.lastTransferTime).toBeDefined();
  });

  test('should export to CSV correctly', () => {
    const entries = [
      {
        id: '1',
        timestamp: 1640000000000,
        sourceDomain: 'example.com',
        destinationUrl: 'https://api.binect.de/upload',
        pdfSize: 1024,
        result: 'success' as const
      },
      {
        id: '2',
        timestamp: 1640000001000,
        sourceDomain: 'test.com',
        destinationUrl: 'https://api.binect.de/upload',
        pdfSize: 2048,
        result: 'failure' as const,
        errorMessage: 'Network error'
      }
    ];

    const csv = exportAsCSV(entries);
    expect(csv).toContain('Timestamp,Source Domain,Destination URL');
    expect(csv).toContain('example.com');
    expect(csv).toContain('test.com');
    expect(csv).toContain('Network error');
  });

  test('should handle CSV escaping', () => {
    const entries = [
      {
        id: '1',
        timestamp: 1640000000000,
        sourceDomain: 'example,with,commas.com',
        destinationUrl: 'https://api.binect.de/upload',
        pdfSize: 1024,
        result: 'success' as const
      }
    ];

    const csv = exportAsCSV(entries);
    expect(csv).toContain('"example,with,commas.com"');
  });

  test('should clear tracking data', async () => {
    await addTrackingEntry({
      timestamp: Date.now(),
      sourceDomain: 'example.com',
      destinationUrl: 'https://api.binect.de/upload',
      pdfSize: 1024,
      result: 'success'
    });

    await clearTracking();

    const entries = await getAllEntries();
    expect(entries.length).toBe(0);
  });
});
