/**
 * Tests for InstallPromptStore
 *
 * Story 3.4: Verify install prompt state management
 */

import { describe, it, expect, beforeEach, vi } from 'vitest';
import { useInstallPromptStore } from './install-prompt-store';
import type { BeforeInstallPromptEvent } from './install-prompt-store';

describe('InstallPromptStore', () => {
  // Create mock event for testing
  const createMockEvent = (): BeforeInstallPromptEvent => {
    return {
      prompt: vi.fn().mockResolvedValue(undefined),
      userChoice: Promise.resolve({ outcome: 'accepted' as const }),
    } as unknown as BeforeInstallPromptEvent;
  };

  beforeEach(() => {
    // Reset store state before each test
    useInstallPromptStore.setState({
      isInstallable: false,
      isInstalled: false,
      deferredPrompt: null
    });
  });

  describe('Initial State', () => {
    it('should initialize with correct default values', () => {
      const { isInstallable, isInstalled, deferredPrompt } = useInstallPromptStore.getState();

      expect(isInstallable).toBe(false);
      expect(isInstalled).toBe(false);
      expect(deferredPrompt).toBeNull();
    });
  });

  describe('setDeferredPrompt', () => {
    it('should set deferredPrompt when provided', () => {
      const mockEvent = createMockEvent();

      useInstallPromptStore.getState().setDeferredPrompt(mockEvent);

      const { deferredPrompt } = useInstallPromptStore.getState();
      expect(deferredPrompt).toBe(mockEvent);
    });

    it('should set isInstallable to true when event is provided', () => {
      const mockEvent = createMockEvent();

      useInstallPromptStore.getState().setDeferredPrompt(mockEvent);

      const { isInstallable } = useInstallPromptStore.getState();
      expect(isInstallable).toBe(true);
    });

    it('should set isInstallable to false when event is null', () => {
      // First set an event
      const mockEvent = createMockEvent();
      useInstallPromptStore.getState().setDeferredPrompt(mockEvent);

      // Then clear it
      useInstallPromptStore.getState().setDeferredPrompt(null);

      const { isInstallable, deferredPrompt } = useInstallPromptStore.getState();
      expect(isInstallable).toBe(false);
      expect(deferredPrompt).toBeNull();
    });
  });

  describe('setInstallable', () => {
    it('should set isInstallable to true', () => {
      useInstallPromptStore.getState().setInstallable(true);

      const { isInstallable } = useInstallPromptStore.getState();
      expect(isInstallable).toBe(true);
    });

    it('should set isInstallable to false', () => {
      useInstallPromptStore.getState().setInstallable(true);
      useInstallPromptStore.getState().setInstallable(false);

      const { isInstallable } = useInstallPromptStore.getState();
      expect(isInstallable).toBe(false);
    });
  });

  describe('setInstalled', () => {
    it('should set isInstalled to true', () => {
      useInstallPromptStore.getState().setInstalled(true);

      const { isInstalled } = useInstallPromptStore.getState();
      expect(isInstalled).toBe(true);
    });

    it('should set isInstalled to false', () => {
      useInstallPromptStore.getState().setInstalled(true);
      useInstallPromptStore.getState().setInstalled(false);

      const { isInstalled } = useInstallPromptStore.getState();
      expect(isInstalled).toBe(false);
    });
  });

  describe('promptInstall', () => {
    it('should return false when no deferredPrompt exists', async () => {
      const result = await useInstallPromptStore.getState().promptInstall();

      expect(result).toBe(false);
    });

    it('should call prompt() on deferredPrompt', async () => {
      const mockEvent = createMockEvent();
      useInstallPromptStore.getState().setDeferredPrompt(mockEvent);

      await useInstallPromptStore.getState().promptInstall();

      expect(mockEvent.prompt).toHaveBeenCalled();
    });

    it('should return true when user accepts install', async () => {
      const mockEvent = createMockEvent();
      useInstallPromptStore.getState().setDeferredPrompt(mockEvent);

      const result = await useInstallPromptStore.getState().promptInstall();

      expect(result).toBe(true);
    });

    it('should set isInstalled to true when user accepts', async () => {
      const mockEvent = createMockEvent();
      useInstallPromptStore.getState().setDeferredPrompt(mockEvent);

      await useInstallPromptStore.getState().promptInstall();

      const { isInstalled } = useInstallPromptStore.getState();
      expect(isInstalled).toBe(true);
    });

    it('should clear deferredPrompt after user accepts', async () => {
      const mockEvent = createMockEvent();
      useInstallPromptStore.getState().setDeferredPrompt(mockEvent);

      await useInstallPromptStore.getState().promptInstall();

      const { deferredPrompt } = useInstallPromptStore.getState();
      expect(deferredPrompt).toBeNull();
    });

    it('should set isInstallable to false after user accepts', async () => {
      const mockEvent = createMockEvent();
      useInstallPromptStore.getState().setDeferredPrompt(mockEvent);

      await useInstallPromptStore.getState().promptInstall();

      const { isInstallable } = useInstallPromptStore.getState();
      expect(isInstallable).toBe(false);
    });

    it('should return false when user dismisses install', async () => {
      const mockEvent = {
        prompt: vi.fn().mockResolvedValue(undefined),
        userChoice: Promise.resolve({ outcome: 'dismissed' as const }),
      } as unknown as BeforeInstallPromptEvent;

      useInstallPromptStore.getState().setDeferredPrompt(mockEvent);

      const result = await useInstallPromptStore.getState().promptInstall();

      expect(result).toBe(false);
    });

    it('should not set isInstalled when user dismisses', async () => {
      const mockEvent = {
        prompt: vi.fn().mockResolvedValue(undefined),
        userChoice: Promise.resolve({ outcome: 'dismissed' as const }),
      } as unknown as BeforeInstallPromptEvent;

      useInstallPromptStore.getState().setDeferredPrompt(mockEvent);

      await useInstallPromptStore.getState().promptInstall();

      const { isInstalled } = useInstallPromptStore.getState();
      expect(isInstalled).toBe(false);
    });
  });

  describe('dismissInstall', () => {
    it('should clear deferredPrompt', () => {
      const mockEvent = createMockEvent();
      useInstallPromptStore.getState().setDeferredPrompt(mockEvent);

      useInstallPromptStore.getState().dismissInstall();

      const { deferredPrompt } = useInstallPromptStore.getState();
      expect(deferredPrompt).toBeNull();
    });

    it('should set isInstallable to false', () => {
      const mockEvent = createMockEvent();
      useInstallPromptStore.getState().setDeferredPrompt(mockEvent);

      useInstallPromptStore.getState().dismissInstall();

      const { isInstallable } = useInstallPromptStore.getState();
      expect(isInstallable).toBe(false);
    });

    it('should not change isInstalled status', () => {
      const mockEvent = createMockEvent();
      useInstallPromptStore.getState().setDeferredPrompt(mockEvent);
      useInstallPromptStore.getState().setInstalled(false);

      useInstallPromptStore.getState().dismissInstall();

      const { isInstalled } = useInstallPromptStore.getState();
      expect(isInstalled).toBe(false);
    });
  });

  describe('Atomic Selectors Pattern', () => {
    it('should allow selecting individual state properties via getState', () => {
      const mockEvent = createMockEvent();

      useInstallPromptStore.getState().setDeferredPrompt(mockEvent);

      // Select individual properties using getState with selector
      const isInstallable = useInstallPromptStore.getState().isInstallable;
      const deferredPrompt = useInstallPromptStore.getState().deferredPrompt;

      expect(isInstallable).toBe(true);
      expect(deferredPrompt).toBe(mockEvent);
    });

    it('should allow using selector function with getState', () => {
      const mockEvent = createMockEvent();

      useInstallPromptStore.getState().setDeferredPrompt(mockEvent);

      // Zustand supports selector functions with getState too
      const state = useInstallPromptStore.getState();
      const isInstallable = state.isInstallable;

      expect(isInstallable).toBe(true);
    });
  });
});
