/**
 * Tests for InstallPromptButton Component
 *
 * Story 3.4: Verify install prompt button behavior
 */

import { describe, it, expect, beforeEach, vi } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { InstallPromptButton } from './InstallPromptButton';
import { useInstallPromptStore } from '@/lib/store/install-prompt-store';
import { EngagementTracker } from '@/services/engagement-tracker';
import { db } from '@/lib/db';
import type { DraftRecord } from '@/lib/db';

// Mock the services
vi.mock('@/services/engagement-tracker', () => ({
  EngagementTracker: {
    hasEngaged: vi.fn(),
  },
}));

vi.mock('@/services/install-prompt-service', () => ({
  InstallPromptService: {
    promptInstall: vi.fn().mockResolvedValue(true),
    dismissInstall: vi.fn(),
  },
}));

describe('InstallPromptButton', () => {
  beforeEach(async () => {
    // Clear database and store state before each test
    await db.delete();
    await db.open();

    useInstallPromptStore.setState({
      isInstallable: false,
      isInstalled: false,
      deferredPrompt: null,
    });

    vi.clearAllMocks();
  });

  describe('Visibility Conditions', () => {
    it('should not render when not installable', () => {
      vi.mocked(EngagementTracker.hasEngaged).mockResolvedValue(true);

      useInstallPromptStore.setState({ isInstallable: false, isInstalled: false });

      const { container } = render(<InstallPromptButton />);

      expect(container.querySelector('button')).toBeNull();
    });

    it('should not render when already installed', () => {
      vi.mocked(EngagementTracker.hasEngaged).mockResolvedValue(true);

      useInstallPromptStore.setState({ isInstallable: true, isInstalled: true });

      const { container } = render(<InstallPromptButton />);

      expect(container.querySelector('button')).toBeNull();
    });

    it('should not render when user has not engaged', async () => {
      vi.mocked(EngagementTracker.hasEngaged).mockResolvedValue(false);

      useInstallPromptStore.setState({ isInstallable: true, isInstalled: false });

      const { container } = render(<InstallPromptButton />);

      await waitFor(() => {
        expect(container.querySelector('button')).toBeNull();
      });
    });

    it('should render when all conditions are met', async () => {
      vi.mocked(EngagementTracker.hasEngaged).mockResolvedValue(true);

      useInstallPromptStore.setState({ isInstallable: true, isInstalled: false });

      render(<InstallPromptButton />);

      await waitFor(() => {
        expect(screen.getByRole('button', { name: /install test01 app/i })).toBeInTheDocument();
      });
    });

    it('should show download icon and install text', async () => {
      vi.mocked(EngagementTracker.hasEngaged).mockResolvedValue(true);

      useInstallPromptStore.setState({ isInstallable: true, isInstalled: false });

      render(<InstallPromptButton />);

      await waitFor(() => {
        expect(screen.getByRole('button', { name: /install test01 app/i })).toBeInTheDocument();
        expect(screen.getByText('Install App')).toBeInTheDocument();
      });
    });

    it('should show "Not now" dismiss button', async () => {
      vi.mocked(EngagementTracker.hasEngaged).mockResolvedValue(true);

      useInstallPromptStore.setState({ isInstallable: true, isInstalled: false });

      render(<InstallPromptButton />);

      await waitFor(() => {
        expect(screen.getByRole('button', { name: /dismiss install prompt/i })).toBeInTheDocument();
        expect(screen.getByText('Not now')).toBeInTheDocument();
      });
    });
  });

  describe('Install Button Click', () => {
    it('should call promptInstall when clicked', async () => {
      const { InstallPromptService } = await import('@/services/install-prompt-service');
      vi.mocked(EngagementTracker.hasEngaged).mockResolvedValue(true);

      useInstallPromptStore.setState({
        isInstallable: true,
        isInstalled: false,
      });

      render(<InstallPromptButton />);

      const button = await screen.findByRole('button', { name: /install test01 app/i });
      await userEvent.click(button);

      await waitFor(() => {
        expect(InstallPromptService.promptInstall).toHaveBeenCalled();
      });
    });
  });

  describe('Dismiss Button Click', () => {
    it('should call dismissInstall when clicked', async () => {
      const { InstallPromptService } = await import('@/services/install-prompt-service');
      vi.mocked(EngagementTracker.hasEngaged).mockResolvedValue(true);

      useInstallPromptStore.setState({ isInstallable: true, isInstalled: false });

      render(<InstallPromptButton />);

      const dismissButton = await screen.findByRole('button', { name: /dismiss install prompt/i });
      await userEvent.click(dismissButton);

      expect(InstallPromptService.dismissInstall).toHaveBeenCalled();
    });
  });

  describe('Atomic Selectors Pattern', () => {
    it('should use atomic selectors from InstallPromptStore', async () => {
      vi.mocked(EngagementTracker.hasEngaged).mockResolvedValue(true);

      useInstallPromptStore.setState({ isInstallable: true, isInstalled: false });

      render(<InstallPromptButton />);

      await waitFor(() => {
        expect(screen.getByRole('button', { name: /install test01 app/i })).toBeInTheDocument();
      });

      // Verify component doesn't break when individual state properties change
      useInstallPromptStore.setState({ isInstallable: false });

      await waitFor(() => {
        expect(screen.queryByRole('button', { name: /install test01 app/i })).not.toBeInTheDocument();
      });
    });
  });
});
