/**
 * TimeSafari Integration Tests
 * 
 * Tests for TimeSafari-specific integration features including
 * privacy-preserving claims, storage adapters, and community features.
 * 
 * @author Matthew Raymer
 * @version 1.0.0
 */

import { 
  TimeSafariIntegrationService
} from '../timesafari-integration';
import {
  TimeSafariStorageAdapterImpl,
  StorageFactory,
  LocalStorageStorage
} from '../timesafari-storage-adapter';
import {
  TimeSafariCommunityIntegrationService
} from '../timesafari-community-integration';

// Mock fetch for testing
global.fetch = jest.fn();

describe('TimeSafari Integration', () => {
  let integrationService: TimeSafariIntegrationService;
  let storageAdapter: TimeSafariStorageAdapterImpl;
  let communityService: TimeSafariCommunityIntegrationService;

  beforeEach(() => {
    // Reset mocks
    jest.clearAllMocks();
    
    // Create fresh instances
    integrationService = TimeSafariIntegrationService.getInstance();
    storageAdapter = new TimeSafariStorageAdapterImpl(new LocalStorageStorage());
    communityService = TimeSafariCommunityIntegrationService.getInstance();
  });

  afterEach(() => {
    // Clean up localStorage
    localStorage.clear();
  });

  describe('TimeSafariIntegrationService', () => {
    test('should initialize with configuration', async () => {
      const config = {
        activeDid: 'did:example:test-123',
        storageAdapter: storageAdapter,
        endorserApiBaseUrl: 'https://test.endorser.ch/api/v1'
      };

      await integrationService.initialize(config);
      
      // Service should be initialized without errors
      expect(integrationService).toBeDefined();
    });

    test('should generate sample DID payloads', () => {
      const payloads = integrationService.generateSampleDidPayloads();
      
      expect(payloads).toHaveLength(2);
      expect(payloads[0].type).toBe('notification_content');
      expect(payloads[1].type).toBe('callback_event');
      expect(payloads[0].verificationSteps).toContain('Extract DID from payload');
    });

    test('should return data retention policy', () => {
      const policy = integrationService.getDataRetentionPolicy();
      
      expect(policy.fields).toBeDefined();
      expect(policy.redactionMethods).toBeDefined();
      expect(policy.storageLocations).toBeDefined();
      expect(policy.fields.activeDid.retention).toBe('session');
      expect(policy.fields.notificationContent.retention).toBe('7_days');
    });

    test('should verify DID signatures (placeholder)', async () => {
      const isValid = await integrationService.verifyDidSignature(
        'test-payload',
        'test-signature'
      );
      
      // Should return false when Veramo stack is not available
      expect(isValid).toBe(false);
    });
  });

  describe('TimeSafariStorageAdapterImpl', () => {
    test('should store and retrieve data', async () => {
      const testData = { message: 'Hello TimeSafari' };
      
      await storageAdapter.store('test-key', testData);
      const retrieved = await storageAdapter.retrieve('test-key');
      
      expect(retrieved).toEqual(testData);
    });

    test('should handle TTL expiration', async () => {
      const testData = { message: 'Expires soon' };
      
      // Store with 1 second TTL
      await storageAdapter.store('ttl-key', testData, 1);
      
      // Should be available immediately
      const retrieved = await storageAdapter.retrieve('ttl-key');
      expect(retrieved).toEqual(testData);
      
      // Wait for expiration
      await new Promise(resolve => setTimeout(resolve, 1100));
      
      // Should be null after expiration
      const expired = await storageAdapter.retrieve('ttl-key');
      expect(expired).toBeNull();
    });

    test('should remove data', async () => {
      const testData = { message: 'To be removed' };
      
      await storageAdapter.store('remove-key', testData);
      await storageAdapter.remove('remove-key');
      
      const retrieved = await storageAdapter.retrieve('remove-key');
      expect(retrieved).toBeNull();
    });

    test('should clear all data', async () => {
      await storageAdapter.store('key1', { data: 1 });
      await storageAdapter.store('key2', { data: 2 });
      
      await storageAdapter.clear();
      
      const retrieved1 = await storageAdapter.retrieve('key1');
      const retrieved2 = await storageAdapter.retrieve('key2');
      
      expect(retrieved1).toBeNull();
      expect(retrieved2).toBeNull();
    });

    test('should provide storage statistics', async () => {
      await storageAdapter.store('stats1', { data: 1 });
      await storageAdapter.store('stats2', { data: 2 });
      
      const stats = await storageAdapter.getStats();
      
      expect(stats.totalKeys).toBe(2);
      expect(stats.validKeys).toBe(2);
      expect(stats.expiredKeys).toBe(0);
      expect(stats.prefix).toBe('timesafari_notifications');
    });
  });

  describe('TimeSafariCommunityIntegrationService', () => {
    test('should initialize with configuration', async () => {
      const config = {
        maxRequestsPerMinute: 10,
        maxRequestsPerHour: 100,
        burstLimit: 5,
        initialBackoffMs: 500,
        maxBackoffMs: 10000,
        basePollingIntervalMs: 60000,
        maxPollingIntervalMs: 300000
      };

      await communityService.initialize(config);
      
      // Service should be initialized without errors
      expect(communityService).toBeDefined();
    });

    test('should provide rate limit status', () => {
      const status = communityService.getRateLimitStatus();
      
      expect(status).toHaveProperty('requestsLastMinute');
      expect(status).toHaveProperty('requestsLastHour');
      expect(status).toHaveProperty('burstRequests');
      expect(status).toHaveProperty('canMakeRequest');
      expect(status).toHaveProperty('waitTime');
    });

    test('should provide backoff status', () => {
      const status = communityService.getBackoffStatus();
      
      expect(status).toHaveProperty('failureCount');
      expect(status).toHaveProperty('currentDelay');
      expect(status).toHaveProperty('isInBackoff');
      expect(status).toHaveProperty('remainingBackoffTime');
    });

    test('should provide polling status', () => {
      const status = communityService.getPollingStatus();
      
      expect(status).toHaveProperty('currentInterval');
      expect(status).toHaveProperty('consecutiveFailures');
      expect(status).toHaveProperty('consecutiveSuccesses');
      expect(status).toHaveProperty('adaptivePolling');
    });

    test('should get optimized polling interval', () => {
      const interval = communityService.getOptimizedPollingInterval();
      
      expect(typeof interval).toBe('number');
      expect(interval).toBeGreaterThan(0);
    });
  });

  describe('StorageFactory', () => {
    test('should create android storage', () => {
      const storage = StorageFactory.createStorage('android');
      
      expect(storage).toBeDefined();
      expect(typeof storage.getItem).toBe('function');
      expect(typeof storage.setItem).toBe('function');
      expect(typeof storage.removeItem).toBe('function');
    });

    test('should create android storage', () => {
      const storage = StorageFactory.createStorage('android');
      
      expect(storage).toBeDefined();
      expect(typeof storage.getItem).toBe('function');
      expect(typeof storage.setItem).toBe('function');
      expect(typeof storage.removeItem).toBe('function');
    });

    test('should create ios storage', () => {
      const storage = StorageFactory.createStorage('ios');
      
      expect(storage).toBeDefined();
      expect(typeof storage.getItem).toBe('function');
      expect(typeof storage.setItem).toBe('function');
      expect(typeof storage.removeItem).toBe('function');
    });

    test('should throw error for unsupported platform', () => {
      expect(() => {
        StorageFactory.createStorage('unsupported' as 'android' | 'ios' | 'electron');
      }).toThrow('Unsupported platform: unsupported');
    });
  });

  describe('Integration Flow', () => {
    test('should complete full integration flow', async () => {
      // Initialize services
      const config = {
        activeDid: 'did:example:integration-test',
        storageAdapter: storageAdapter,
        endorserApiBaseUrl: 'https://test.endorser.ch/api/v1'
      };

      await integrationService.initialize(config);
      await communityService.initialize({
        maxRequestsPerMinute: 30,
        maxRequestsPerHour: 1000
      });

      // Store sample data
      await storageAdapter.store('integration-test', {
        timestamp: Date.now(),
        data: 'integration test data'
      });

      // Retrieve data
      const retrieved = await storageAdapter.retrieve('integration-test');
      expect(retrieved).toBeDefined();
      expect((retrieved as { data: string }).data).toBe('integration test data');

      // Get status from all services
      const rateLimitStatus = communityService.getRateLimitStatus();
      const backoffStatus = communityService.getBackoffStatus();
      const pollingStatus = communityService.getPollingStatus();

      expect(rateLimitStatus.canMakeRequest).toBe(true);
      expect(backoffStatus.isInBackoff).toBe(false);
      expect(pollingStatus.currentInterval).toBeGreaterThan(0);

      // Generate sample payloads
      const payloads = integrationService.generateSampleDidPayloads();
      expect(payloads.length).toBeGreaterThan(0);

      // Get data retention policy
      const policy = integrationService.getDataRetentionPolicy();
      expect(policy.fields).toBeDefined();
    });
  });
});
