/**
 * Service Integration Tests
 * 
 * Tests for TimeSafari service integration layer including
 * DailyNotificationService, DatabaseIntegrationService, and PlatformServiceMixin.
 * 
 * @author Matthew Raymer
 * @version 1.0.0
 */

import {
  DailyNotificationService,
  DailyNotificationServiceConfig
} from '../services/DailyNotificationService';

import {
  DatabaseIntegrationService,
  DatabaseIntegrationConfig
} from '../services/DatabaseIntegrationService';

import {
  TimeSafariDailyNotificationMixin,
  TimeSafariDailyNotificationExample,
  WithTimeSafariDailyNotifications
} from '../utils/PlatformServiceMixin';

import {
  TimeSafariStorageAdapterImpl,
  LocalStorageStorage
} from '../timesafari-storage-adapter';

// Mock Vue for testing (not used in simplified version)

// Note: Native platform implementations are handled by the service layer
// No mocking needed as we're testing the service integration, not the native implementations

describe('Service Integration', () => {
  let dailyNotificationService: DailyNotificationService;
  let databaseIntegrationService: DatabaseIntegrationService;
  let storageAdapter: TimeSafariStorageAdapterImpl;

  beforeEach(() => {
    // Reset mocks
    jest.clearAllMocks();
    
    // Create fresh instances
    dailyNotificationService = DailyNotificationService.getInstance();
    databaseIntegrationService = DatabaseIntegrationService.getInstance();
    storageAdapter = new TimeSafariStorageAdapterImpl(new LocalStorageStorage());
  });

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

  describe('DailyNotificationService', () => {
    test('should initialize with configuration', async () => {
      const config: DailyNotificationServiceConfig = {
        activeDid: 'did:example:test-123',
        storageAdapter: storageAdapter,
        platform: 'android',
        logging: {
          level: 'info',
          enableStructuredLogging: true,
          enableEventIds: true,
          enablePerformanceMetrics: true
        }
      };

      await dailyNotificationService.initialize(config);
      
      const status = dailyNotificationService.getStatus();
      expect(status.initialized).toBe(true);
      expect(status.activeDid).toBe('did:example:test-123');
      expect(status.platform).toBe('android');
    });

    test('should schedule daily notification', async () => {
      const config: DailyNotificationServiceConfig = {
        activeDid: 'did:example:test-123',
        storageAdapter: storageAdapter,
        platform: 'android'
      };

      await dailyNotificationService.initialize(config);
      
      const options = {
        title: 'Test Notification',
        body: 'Test notification body',
        time: '09:00',
        channel: 'timesafari_community_updates'
      };

      await dailyNotificationService.scheduleDailyNotification(options);
      
      // Verify notification was scheduled (native platform handles this)
      // The service logs indicate successful scheduling
    });

    test('should fetch community data', async () => {
      const config: DailyNotificationServiceConfig = {
        activeDid: 'did:example:test-123',
        storageAdapter: storageAdapter,
        platform: 'android'
      };

      await dailyNotificationService.initialize(config);
      
      // This would normally call the community service
      // For testing, we'll just verify the service is initialized
      const status = dailyNotificationService.getStatus();
      expect(status.initialized).toBe(true);
    });

    test('should provide service status', async () => {
      const config: DailyNotificationServiceConfig = {
        activeDid: 'did:example:test-123',
        storageAdapter: storageAdapter,
        platform: 'android'
      };

      await dailyNotificationService.initialize(config);
      
      const status = dailyNotificationService.getStatus();
      expect(status).toHaveProperty('initialized');
      expect(status).toHaveProperty('activeDid');
      expect(status).toHaveProperty('platform');
      expect(status).toHaveProperty('circuitBreakerState');
      expect(status).toHaveProperty('totalRequests');
      expect(status).toHaveProperty('successfulRequests');
      expect(status).toHaveProperty('failedRequests');
      expect(status).toHaveProperty('uptime');
    });

    test('should handle circuit breaker', async () => {
      const config: DailyNotificationServiceConfig = {
        activeDid: 'did:example:test-123',
        storageAdapter: storageAdapter,
        platform: 'android',
        circuitBreaker: {
          failureThreshold: 2,
          recoveryTimeout: 1000,
          monitoringPeriod: 1000,
          halfOpenMaxCalls: 1
        }
      };

      await dailyNotificationService.initialize(config);
      
      const circuitBreakerStatus = dailyNotificationService.getCircuitBreakerStatus();
      expect(circuitBreakerStatus.state).toBe('closed');
      expect(circuitBreakerStatus.failures).toBe(0);
    });

    test('should shutdown gracefully', async () => {
      const config: DailyNotificationServiceConfig = {
        activeDid: 'did:example:test-123',
        storageAdapter: storageAdapter,
        platform: 'android'
      };

      await dailyNotificationService.initialize(config);
      await dailyNotificationService.shutdown();
      
      const status = dailyNotificationService.getStatus();
      expect(status.initialized).toBe(false);
    });
  });

  describe('DatabaseIntegrationService', () => {
    test('should initialize with configuration', async () => {
      const config: DatabaseIntegrationConfig = {
        platform: 'android',
        storageAdapter: storageAdapter,
        database: {
          name: 'test_db',
          version: 1,
          tables: [],
          migrations: []
        },
        watermark: {
          enabled: true,
          tableName: 'watermarks',
          columnName: 'value',
          initialValue: 0,
          updateInterval: 1000
        }
      };

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

    test('should store notification data', async () => {
      const config: DatabaseIntegrationConfig = {
        platform: 'android',
        storageAdapter: storageAdapter
      };

      await databaseIntegrationService.initialize(config);
      
      const notificationData = {
        id: 'test-notification-123',
        title: 'Test Notification',
        body: 'Test notification body',
        scheduledTime: Date.now(),
        channel: 'timesafari_community_updates',
        activeDid: 'did:example:test-123',
        metadata: { test: true }
      };

      await databaseIntegrationService.storeNotificationData(notificationData);
      
      // Verify data was stored
      const retrieved = await storageAdapter.retrieve('notification_test-notification-123');
      expect(retrieved).toBeDefined();
      expect((retrieved as { title: string; body: string }).title).toBe(notificationData.title);
      expect((retrieved as { title: string; body: string }).body).toBe(notificationData.body);
    });

    test('should retrieve notification data', async () => {
      const config: DatabaseIntegrationConfig = {
        platform: 'android',
        storageAdapter: storageAdapter
      };

      await databaseIntegrationService.initialize(config);
      
      const notificationData = {
        id: 'test-notification-456',
        title: 'Test Notification 2',
        body: 'Test notification body 2',
        scheduledTime: Date.now(),
        channel: 'timesafari_project_notifications',
        activeDid: 'did:example:test-123'
      };

      await databaseIntegrationService.storeNotificationData(notificationData);
      
      const retrieved = await databaseIntegrationService.retrieveNotificationData('test-notification-456');
      expect(retrieved).toBeDefined();
      expect((retrieved as { title: string }).title).toBe(notificationData.title);
    });

    test('should manage watermark', async () => {
      const config: DatabaseIntegrationConfig = {
        platform: 'android',
        storageAdapter: storageAdapter,
        watermark: {
          enabled: true,
          tableName: 'watermarks',
          columnName: 'value',
          initialValue: 0,
          updateInterval: 1000
        }
      };

      await databaseIntegrationService.initialize(config);
      
      const newWatermark = 12345;
      await databaseIntegrationService.updateWatermark(newWatermark);
      
      const currentWatermark = await databaseIntegrationService.getWatermark();
      expect(currentWatermark).toBe(newWatermark);
    });

    test('should provide database statistics', async () => {
      const config: DatabaseIntegrationConfig = {
        platform: 'android',
        storageAdapter: storageAdapter
      };

      await databaseIntegrationService.initialize(config);
      
      const stats = await databaseIntegrationService.getDatabaseStats();
      expect(stats).toHaveProperty('totalNotifications');
      expect(stats).toHaveProperty('totalStorageSize');
      expect(stats).toHaveProperty('watermarkValue');
      expect(stats).toHaveProperty('lastUpdated');
    });

    test('should cleanup expired data', async () => {
      const config: DatabaseIntegrationConfig = {
        platform: 'android',
        storageAdapter: storageAdapter
      };

      await databaseIntegrationService.initialize(config);
      
      // Store some data with short TTL
      await storageAdapter.store('test-expired', { data: 'test' }, 1); // 1 second TTL
      
      // Wait for expiration
      await new Promise(resolve => setTimeout(resolve, 1100));
      
      await databaseIntegrationService.cleanupExpiredData();
      
      // Verify expired data was cleaned up
      const retrieved = await storageAdapter.retrieve('test-expired');
      expect(retrieved).toBeNull();
    });

    test('should shutdown gracefully', async () => {
      const config: DatabaseIntegrationConfig = {
        platform: 'android',
        storageAdapter: storageAdapter
      };

      await databaseIntegrationService.initialize(config);
      await databaseIntegrationService.shutdown();
      
      // Service should be shut down without errors
      expect(databaseIntegrationService).toBeDefined();
    });
  });

  describe('PlatformServiceMixin', () => {
    test('should create mixin instance', () => {
      const mixin = new TimeSafariDailyNotificationMixin();
      expect(mixin).toBeDefined();
      expect(mixin.dailyNotificationService).toBeDefined();
    });

    test('should have required methods', () => {
      const mixin = new TimeSafariDailyNotificationMixin();
      
      expect(typeof mixin.initializeDailyNotifications).toBe('function');
      expect(typeof mixin.scheduleDailyNotification).toBe('function');
      expect(typeof mixin.fetchCommunityData).toBe('function');
      expect(typeof mixin.getServiceStatus).toBe('function');
      expect(typeof mixin.shutdownDailyNotifications).toBe('function');
    });

    test('should have service status methods', () => {
      const mixin = new TimeSafariDailyNotificationMixin();
      
      expect(mixin.isServiceReady()).toBe(false);
      expect(mixin.getServiceStatusData()).toBe(null);
      expect(mixin.getServiceError()).toBe(null);
    });

    test('should create example component', () => {
      const example = new TimeSafariDailyNotificationExample();
      expect(example).toBeDefined();
      expect(example.dailyNotificationService).toBeDefined();
    });

    test('should create decorator example component', () => {
      class TestComponent {
        [key: string]: unknown;
      }
      const DecoratedComponent = WithTimeSafariDailyNotifications(TestComponent);
      const decoratorExample = new DecoratedComponent();
      expect(decoratorExample).toBeDefined();
      expect((decoratorExample as { dailyNotificationService: unknown }).dailyNotificationService).toBeDefined();
    });
  });

  describe('Service Integration Flow', () => {
    test('should complete full service integration flow', async () => {
      // Initialize DailyNotificationService
      const dailyConfig: DailyNotificationServiceConfig = {
        activeDid: 'did:example:integration-test',
        storageAdapter: storageAdapter,
        platform: 'android'
      };

      await dailyNotificationService.initialize(dailyConfig);
      
      // Initialize DatabaseIntegrationService
      const dbConfig: DatabaseIntegrationConfig = {
        platform: 'android',
        storageAdapter: storageAdapter
      };

      await databaseIntegrationService.initialize(dbConfig);
      
      // Schedule a notification
      await dailyNotificationService.scheduleDailyNotification({
        title: 'Integration Test Notification',
        body: 'Testing full service integration',
        time: '10:00',
        channel: 'timesafari_community_updates'
      });
      
      // Store notification data
      await databaseIntegrationService.storeNotificationData({
        id: 'integration-test-123',
        title: 'Integration Test Notification',
        body: 'Testing full service integration',
        scheduledTime: Date.now(),
        channel: 'timesafari_community_updates',
        activeDid: 'did:example:integration-test'
      });
      
      // Verify services are working
      const dailyStatus = dailyNotificationService.getStatus();
      const dbStats = await databaseIntegrationService.getDatabaseStats();
      
      expect(dailyStatus.initialized).toBe(true);
      expect(dbStats.totalNotifications).toBeGreaterThanOrEqual(0);
      
      // Shutdown services
      await dailyNotificationService.shutdown();
      await databaseIntegrationService.shutdown();
      
      // Get status after shutdown
      const finalStatus = dailyNotificationService.getStatus();
      expect(finalStatus.initialized).toBe(false);
    });
  });
});
