/**
 * Test Initialization Script
 * Standalone initialization for test pages without requiring full calendar DOM
 */

// IndexedDB Service (simplified standalone version)
class TestIndexedDBService {
  constructor() {
    this.DB_NAME = 'CalendarDB_Test'; // Separate test database
    this.DB_VERSION = 1;
    this.EVENTS_STORE = 'events';
    this.QUEUE_STORE = 'operationQueue';
    this.SYNC_STATE_STORE = 'syncState';
    this.db = null;
  }

  async initialize() {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open(this.DB_NAME, this.DB_VERSION);

      request.onerror = () => reject(request.error);
      request.onsuccess = () => {
        this.db = request.result;
        resolve();
      };

      request.onupgradeneeded = (event) => {
        const db = event.target.result;

        // Create events store
        if (!db.objectStoreNames.contains(this.EVENTS_STORE)) {
          const eventStore = db.createObjectStore(this.EVENTS_STORE, { keyPath: 'id' });
          eventStore.createIndex('start', 'start', { unique: false });
          eventStore.createIndex('end', 'end', { unique: false });
          eventStore.createIndex('syncStatus', 'syncStatus', { unique: false });
        }

        // Create operation queue store
        if (!db.objectStoreNames.contains(this.QUEUE_STORE)) {
          const queueStore = db.createObjectStore(this.QUEUE_STORE, { keyPath: 'id', autoIncrement: true });
          queueStore.createIndex('timestamp', 'timestamp', { unique: false });
          queueStore.createIndex('eventId', 'eventId', { unique: false });
        }

        // Create sync state store
        if (!db.objectStoreNames.contains(this.SYNC_STATE_STORE)) {
          db.createObjectStore(this.SYNC_STATE_STORE, { keyPath: 'key' });
        }
      };
    });
  }

  async getAllEvents() {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.EVENTS_STORE], 'readonly');
      const store = transaction.objectStore(this.EVENTS_STORE);
      const request = store.getAll();

      request.onsuccess = () => {
        const events = request.result.map(event => ({
          ...event,
          start: new Date(event.start),
          end: new Date(event.end)
        }));
        resolve(events);
      };
      request.onerror = () => reject(request.error);
    });
  }

  async getEvent(id) {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.EVENTS_STORE], 'readonly');
      const store = transaction.objectStore(this.EVENTS_STORE);
      const request = store.get(id);

      request.onsuccess = () => {
        const event = request.result;
        if (event) {
          event.start = new Date(event.start);
          event.end = new Date(event.end);
        }
        resolve(event || null);
      };
      request.onerror = () => reject(request.error);
    });
  }

  async saveEvent(event) {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.EVENTS_STORE], 'readwrite');
      const store = transaction.objectStore(this.EVENTS_STORE);
      const eventToSave = {
        ...event,
        start: event.start instanceof Date ? event.start.toISOString() : event.start,
        end: event.end instanceof Date ? event.end.toISOString() : event.end
      };
      const request = store.put(eventToSave);

      request.onsuccess = () => resolve();
      request.onerror = () => reject(request.error);
    });
  }

  async deleteEvent(id) {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.EVENTS_STORE], 'readwrite');
      const store = transaction.objectStore(this.EVENTS_STORE);
      const request = store.delete(id);

      request.onsuccess = () => resolve();
      request.onerror = () => reject(request.error);
    });
  }

  async addToQueue(operation) {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.QUEUE_STORE], 'readwrite');
      const store = transaction.objectStore(this.QUEUE_STORE);
      const request = store.add(operation);

      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(request.error);
    });
  }

  async getQueue() {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.QUEUE_STORE], 'readonly');
      const store = transaction.objectStore(this.QUEUE_STORE);
      const request = store.getAll();

      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(request.error);
    });
  }

  async removeFromQueue(id) {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.QUEUE_STORE], 'readwrite');
      const store = transaction.objectStore(this.QUEUE_STORE);
      const request = store.delete(id);

      request.onsuccess = () => resolve();
      request.onerror = () => reject(request.error);
    });
  }

  async clearQueue() {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.QUEUE_STORE], 'readwrite');
      const store = transaction.objectStore(this.QUEUE_STORE);
      const request = store.clear();

      request.onsuccess = () => resolve();
      request.onerror = () => reject(request.error);
    });
  }

  close() {
    if (this.db) {
      this.db.close();
    }
  }
}

// Operation Queue (simplified standalone version)
class TestOperationQueue {
  constructor(indexedDB) {
    this.indexedDB = indexedDB;
  }

  async enqueue(operation) {
    await this.indexedDB.addToQueue(operation);
  }

  async getAll() {
    return await this.indexedDB.getQueue();
  }

  async remove(id) {
    await this.indexedDB.removeFromQueue(id);
  }

  async clear() {
    await this.indexedDB.clearQueue();
  }

  async incrementRetryCount(operationId) {
    const queue = await this.getAll();
    const operation = queue.find(op => op.id === operationId);
    if (operation) {
      operation.retryCount = (operation.retryCount || 0) + 1;
      await this.indexedDB.removeFromQueue(operationId);
      await this.indexedDB.addToQueue(operation);
    }
  }
}

// Simple EventManager for tests
class TestEventManager {
  constructor(indexedDB, queue) {
    this.indexedDB = indexedDB;
    this.queue = queue;
  }

  async getAllEvents() {
    return await this.indexedDB.getAllEvents();
  }

  async getEvent(id) {
    return await this.indexedDB.getEvent(id);
  }

  async addEvent(eventData) {
    const id = eventData.id || `event_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    const syncStatus = eventData.syncStatus || 'pending';

    const newEvent = {
      ...eventData,
      id,
      syncStatus
    };

    await this.indexedDB.saveEvent(newEvent);

    if (syncStatus === 'pending') {
      await this.queue.enqueue({
        type: 'create',
        eventId: id,
        data: newEvent,
        timestamp: Date.now(),
        retryCount: 0
      });
    }

    return newEvent;
  }

  async updateEvent(id, updates) {
    const event = await this.indexedDB.getEvent(id);
    if (!event) return null;

    const updatedEvent = { ...event, ...updates, syncStatus: 'pending' };
    await this.indexedDB.saveEvent(updatedEvent);

    await this.queue.enqueue({
      type: 'update',
      eventId: id,
      data: updates,
      timestamp: Date.now(),
      retryCount: 0
    });

    return updatedEvent;
  }

  async deleteEvent(id) {
    await this.indexedDB.deleteEvent(id);
    await this.queue.enqueue({
      type: 'delete',
      eventId: id,
      data: null,
      timestamp: Date.now(),
      retryCount: 0
    });
  }
}

// Minimal SyncManager for tests with mock API simulation
class TestSyncManager {
  constructor(queue, indexedDB) {
    this.queue = queue;
    this.indexedDB = indexedDB;
    this.isOnline = navigator.onLine;
    this.maxRetries = 5;
    this.setupNetworkListeners();
  }

  setupNetworkListeners() {
    window.addEventListener('online', () => {
      this.isOnline = true;
      console.log('[TestSyncManager] Network online');
    });

    window.addEventListener('offline', () => {
      this.isOnline = false;
      console.log('[TestSyncManager] Network offline');
    });
  }

  async triggerManualSync() {
    console.log('[TestSyncManager] Manual sync triggered');

    // Check if online before syncing
    if (!this.isOnline) {
      console.warn('[TestSyncManager] ⚠️ Cannot sync - offline mode');
      throw new Error('Cannot sync while offline');
    }

    const queueItems = await this.queue.getAll();
    console.log(`[TestSyncManager] Queue has ${queueItems.length} items`);

    if (queueItems.length === 0) {
      console.log('[TestSyncManager] Queue is empty - nothing to sync');
      return [];
    }

    // Process each operation
    for (const operation of queueItems) {
      await this.processOperation(operation);
    }

    return queueItems;
  }

  async processOperation(operation) {
    console.log(`[TestSyncManager] Processing operation ${operation.id} (retry: ${operation.retryCount})`);

    // Check if max retries exceeded
    if (operation.retryCount >= this.maxRetries) {
      console.error(`[TestSyncManager] Max retries (${this.maxRetries}) exceeded for operation ${operation.id}`);
      await this.queue.remove(operation.id);
      await this.markEventAsError(operation.eventId);
      return;
    }

    // Simulate API call with delay
    await this.simulateApiCall();

    // Simulate success (80%) or failure (20%)
    const success = Math.random() > 0.2;

    if (success) {
      console.log(`[TestSyncManager] ✓ Operation ${operation.id} synced successfully`);
      await this.queue.remove(operation.id);
      await this.markEventAsSynced(operation.eventId);
    } else {
      console.warn(`[TestSyncManager] ✗ Operation ${operation.id} failed - will retry`);
      await this.queue.incrementRetryCount(operation.id);
    }
  }

  async simulateApiCall() {
    // Simulate network delay (100-500ms)
    const delay = Math.floor(Math.random() * 400) + 100;
    return new Promise(resolve => setTimeout(resolve, delay));
  }

  async markEventAsSynced(eventId) {
    try {
      const event = await this.indexedDB.getEvent(eventId);
      if (event) {
        event.syncStatus = 'synced';
        await this.indexedDB.saveEvent(event);
        console.log(`[TestSyncManager] Event ${eventId} marked as synced`);
      }
    } catch (error) {
      console.error(`[TestSyncManager] Failed to mark event ${eventId} as synced:`, error);
    }
  }

  async markEventAsError(eventId) {
    try {
      const event = await this.indexedDB.getEvent(eventId);
      if (event) {
        event.syncStatus = 'error';
        await this.indexedDB.saveEvent(event);
        console.log(`[TestSyncManager] Event ${eventId} marked as error`);
      }
    } catch (error) {
      console.error(`[TestSyncManager] Failed to mark event ${eventId} as error:`, error);
    }
  }
}

// Initialize test environment
async function initializeTestEnvironment() {
  console.log('[Test Init] Initializing test environment...');

  const indexedDB = new TestIndexedDBService();
  await indexedDB.initialize();
  console.log('[Test Init] IndexedDB initialized');

  const queue = new TestOperationQueue(indexedDB);
  console.log('[Test Init] Operation queue created');

  const eventManager = new TestEventManager(indexedDB, queue);
  console.log('[Test Init] Event manager created');

  const syncManager = new TestSyncManager(queue, indexedDB);
  console.log('[Test Init] Sync manager created');

  // Seed with test data if empty
  const existingEvents = await indexedDB.getAllEvents();
  if (existingEvents.length === 0) {
    console.log('[Test Init] Seeding with test data...');
    try {
      const response = await fetch('test-events.json');
      const testEvents = await response.json();
      for (const event of testEvents) {
        const savedEvent = {
          ...event,
          start: new Date(event.start),
          end: new Date(event.end)
        };
        await indexedDB.saveEvent(savedEvent);

        // If event is pending, also add to queue
        if (event.syncStatus === 'pending') {
          await queue.enqueue({
            type: 'create',
            eventId: event.id,
            data: savedEvent,
            timestamp: Date.now(),
            retryCount: 0
          });
          console.log(`[Test Init] Added pending event ${event.id} to queue`);
        }
      }
      console.log(`[Test Init] Seeded ${testEvents.length} test events`);
    } catch (error) {
      console.warn('[Test Init] Could not load test-events.json:', error);
    }
  } else {
    console.log(`[Test Init] IndexedDB already has ${existingEvents.length} events`);
  }

  // Expose to window
  window.calendarDebug = {
    indexedDB,
    queue,
    eventManager,
    syncManager
  };

  console.log('[Test Init] Test environment ready');
  return { indexedDB, queue, eventManager, syncManager };
}

// Auto-initialize if script is loaded
if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', () => {
    initializeTestEnvironment().catch(error => {
      console.error('[Test Init] Failed to initialize:', error);
    });
  });
} else {
  initializeTestEnvironment().catch(error => {
    console.error('[Test Init] Failed to initialize:', error);
  });
}
