import { describe, it, expect, beforeEach } from 'vitest';
import { db } from '../db';
import { useOfflineStore } from './offline-store';

describe('Story 3.3: OfflineStore', () => {
  beforeEach(async () => {
    // Clear syncQueue table before each test
    await db.syncQueue.clear();

    // Reset store state
    useOfflineStore.setState({
      isOnline: true,
      pendingCount: 0,
      lastSyncAt: null,
      syncing: false,
    });
  });

  describe('initial state', () => {
    it('should have correct initial state', () => {
      const state = useOfflineStore.getState();

      expect(state.isOnline).toBe(true); // Default to online
      expect(state.pendingCount).toBe(0);
      expect(state.lastSyncAt).toBeNull();
      expect(state.syncing).toBe(false);
    });
  });

  describe('setOnlineStatus', () => {
    it('should update isOnline status', () => {
      const { setOnlineStatus } = useOfflineStore.getState();

      setOnlineStatus(false);
      expect(useOfflineStore.getState().isOnline).toBe(false);

      setOnlineStatus(true);
      expect(useOfflineStore.getState().isOnline).toBe(true);
    });

    it('should update pendingCount when going online', async () => {
      // Add some pending items to queue
      await db.syncQueue.add({
        action: 'saveDraft',
        payload: {
          draftData: {
            sessionId: 'test',
            title: 'Test',
            content: 'Test',
            tags: [],
            createdAt: Date.now(),
            status: 'draft',
          },
        },
        status: 'pending',
        createdAt: Date.now(),
        retries: 0,
      });

      const { setOnlineStatus } = useOfflineStore.getState();
      setOnlineStatus(true);

      // Should trigger updatePendingCount
      await new Promise(resolve => setTimeout(resolve, 0));

      expect(useOfflineStore.getState().pendingCount).toBe(1);
    });
  });

  describe('syncNow', () => {
    it('should set syncing to true during sync', async () => {
      // Add a pending item
      await db.syncQueue.add({
        action: 'deleteDraft',
        payload: { draftId: 1 },
        status: 'pending',
        createdAt: Date.now(),
        retries: 0,
      });

      const { syncNow } = useOfflineStore.getState();

      const syncPromise = syncNow();
      expect(useOfflineStore.getState().syncing).toBe(true);

      await syncPromise;
      expect(useOfflineStore.getState().syncing).toBe(false);
    });

    it('should update lastSyncAt after sync', async () => {
      const before = useOfflineStore.getState().lastSyncAt;
      expect(before).toBeNull();

      const { syncNow } = useOfflineStore.getState();
      await syncNow();

      const after = useOfflineStore.getState().lastSyncAt;
      expect(after).not.toBeNull();
      expect(after).toBeGreaterThan(Date.now() - 1000); // Within last second
    });

    it('should update pendingCount after sync', async () => {
      // Create a draft first
      const draftId = await db.drafts.add({
        sessionId: 'test',
        title: 'Test',
        content: 'Test',
        tags: [],
        createdAt: Date.now(),
        status: 'draft',
      });

      // Add a pending item to delete it
      await db.syncQueue.add({
        action: 'deleteDraft',
        payload: { draftId },
        status: 'pending',
        createdAt: Date.now(),
        retries: 0,
      });

      const { updatePendingCount } = useOfflineStore.getState();
      await updatePendingCount();
      expect(useOfflineStore.getState().pendingCount).toBe(1);

      const { syncNow } = useOfflineStore.getState();
      await syncNow();

      // Queue should be empty after processing
      await updatePendingCount();
      expect(useOfflineStore.getState().pendingCount).toBe(0);
    });
  });

  describe('updatePendingCount', () => {
    it('should count pending items in queue', async () => {
      // Add pending items
      await db.syncQueue.add({
        action: 'saveDraft',
        payload: {
          draftData: {
            sessionId: 'test',
            title: 'Test',
            content: 'Test',
            tags: [],
            createdAt: Date.now(),
            status: 'draft',
          },
        },
        status: 'pending',
        createdAt: Date.now(),
        retries: 0,
      });

      await db.syncQueue.add({
        action: 'deleteDraft',
        payload: { draftId: 1 },
        status: 'pending',
        createdAt: Date.now(),
        retries: 0,
      });

      // Add non-pending items (should not be counted)
      await db.syncQueue.add({
        action: 'saveDraft',
        payload: {
          draftData: {
            sessionId: 'test2',
            title: 'Test2',
            content: 'Test2',
            tags: [],
            createdAt: Date.now(),
            status: 'draft',
          },
        },
        status: 'synced',
        createdAt: Date.now(),
        retries: 0,
      });

      const { updatePendingCount } = useOfflineStore.getState();
      await updatePendingCount();

      expect(useOfflineStore.getState().pendingCount).toBe(2);
    });

    it('should return 0 for empty queue', async () => {
      const { updatePendingCount } = useOfflineStore.getState();
      await updatePendingCount();

      expect(useOfflineStore.getState().pendingCount).toBe(0);
    });
  });

  describe('atomic selectors', () => {
    it('should provide atomic selectors for performance', () => {
      // Test that we can get state using getState
      // Atomic selectors are used in React components, not in tests
      const state = useOfflineStore.getState();

      expect(typeof state.isOnline).toBe('boolean');
      expect(typeof state.pendingCount).toBe('number');
      expect(typeof state.syncing).toBe('boolean');
    });
  });
});
