/**
 * Unit tests for OnboardingWizard component
 *
 * Tests the multi-step onboarding wizard for new businesses.
 * Covers:
 * - Step navigation (welcome -> stripe -> complete)
 * - Step indicator visualization
 * - Welcome step rendering and buttons
 * - Stripe Connect integration step
 * - Completion step
 * - Skip functionality
 * - Auto-advance on Stripe connection
 * - URL parameter handling (OAuth callback)
 * - Loading states
 * - Business update on completion
 */

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { BrowserRouter, useSearchParams } from 'react-router-dom';
import OnboardingWizard from '../OnboardingWizard';
import { Business } from '../../types';

// Mock hooks
const mockUsePaymentConfig = vi.fn();
const mockUseUpdateBusiness = vi.fn();
const mockSetSearchParams = vi.fn();
const mockSearchParams = new URLSearchParams();

vi.mock('../../hooks/usePayments', () => ({
  usePaymentConfig: () => mockUsePaymentConfig(),
}));

vi.mock('../../hooks/useBusiness', () => ({
  useUpdateBusiness: () => mockUseUpdateBusiness(),
}));

vi.mock('react-router-dom', async () => {
  const actual = await vi.importActual('react-router-dom');
  return {
    ...actual,
    useSearchParams: () => [mockSearchParams, mockSetSearchParams],
  };
});

// Mock ConnectOnboardingEmbed component
vi.mock('../ConnectOnboardingEmbed', () => ({
  default: ({ onComplete, onError }: any) => (
    <div data-testid="connect-embed">
      <button onClick={() => onComplete()}>Complete Embed</button>
      <button onClick={() => onError('Test error')}>Trigger Error</button>
    </div>
  ),
}));

// Mock react-i18next
vi.mock('react-i18next', () => ({
  useTranslation: () => ({
    t: (key: string, params?: Record<string, unknown>) => {
      const translations: Record<string, string> = {
        'onboarding.steps.welcome': 'Welcome',
        'onboarding.steps.payments': 'Payments',
        'onboarding.steps.complete': 'Complete',
        'onboarding.welcome.title': `Welcome to ${params?.businessName}!`,
        'onboarding.welcome.subtitle': "Let's get you set up",
        'onboarding.welcome.whatsIncluded': "What's Included",
        'onboarding.welcome.connectStripe': 'Connect to Stripe',
        'onboarding.welcome.automaticPayouts': 'Automatic payouts',
        'onboarding.welcome.pciCompliance': 'PCI compliance',
        'onboarding.welcome.getStarted': 'Get Started',
        'onboarding.welcome.skip': 'Skip for now',
        'onboarding.stripe.title': 'Connect Stripe',
        'onboarding.stripe.subtitle': `Accept payments with your ${params?.plan} plan`,
        'onboarding.stripe.checkingStatus': 'Checking status...',
        'onboarding.stripe.connected.title': 'Connected!',
        'onboarding.stripe.connected.subtitle': 'Your account is ready',
        'onboarding.stripe.continue': 'Continue',
        'onboarding.stripe.doLater': 'Do this later',
        'onboarding.complete.title': "You're all set!",
        'onboarding.complete.subtitle': 'Ready to start',
        'onboarding.complete.checklist.accountCreated': 'Account created',
        'onboarding.complete.checklist.stripeConfigured': 'Stripe configured',
        'onboarding.complete.checklist.readyForPayments': 'Ready for payments',
        'onboarding.complete.goToDashboard': 'Go to Dashboard',
        'onboarding.skipForNow': 'Skip for now',
      };
      return translations[key] || key;
    },
  }),
}));

// Test data factory
const createMockBusiness = (overrides?: Partial<Business>): Business => ({
  id: '1',
  name: 'Test Business',
  subdomain: 'testbiz',
  primaryColor: '#3B82F6',
  secondaryColor: '#1E40AF',
  whitelabelEnabled: false,
  paymentsEnabled: false,
  requirePaymentMethodToBook: false,
  cancellationWindowHours: 24,
  lateCancellationFeePercent: 50,
  plan: 'Professional',
  ...overrides,
});

// Helper to wrap component with providers
const createWrapper = () => {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: { retry: false },
      mutations: { retry: false },
    },
  });
  return ({ children }: { children: React.ReactNode }) => (
    <QueryClientProvider client={queryClient}>
      <BrowserRouter>{children}</BrowserRouter>
    </QueryClientProvider>
  );
};

describe('OnboardingWizard', () => {
  const mockOnComplete = vi.fn();
  const mockOnSkip = vi.fn();
  const mockRefetch = vi.fn();
  const mockMutateAsync = vi.fn();

  beforeEach(() => {
    vi.clearAllMocks();
    mockSearchParams.delete('connect');

    mockUsePaymentConfig.mockReturnValue({
      data: {
        connect_account: null,
      },
      isLoading: false,
      refetch: mockRefetch,
    });

    mockUseUpdateBusiness.mockReturnValue({
      mutateAsync: mockMutateAsync,
      isPending: false,
    });
  });

  describe('Modal Rendering', () => {
    it('should render modal overlay', () => {
      const business = createMockBusiness();

      const { container } = render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      // Modal has the fixed class for overlay
      const modal = container.querySelector('.fixed');
      expect(modal).toBeInTheDocument();
      expect(modal).toHaveClass('inset-0');
    });

    it('should render close button', () => {
      const business = createMockBusiness();

      render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      const closeButton = screen.getAllByRole('button').find(btn =>
        btn.querySelector('svg')
      );
      expect(closeButton).toBeInTheDocument();
    });

    it('should have scrollable content', () => {
      const business = createMockBusiness();

      const { container } = render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      const modal = container.querySelector('.overflow-auto');
      expect(modal).toBeInTheDocument();
    });
  });

  describe('Step Indicator', () => {
    it('should render step indicator with 3 steps', () => {
      const business = createMockBusiness();

      const { container } = render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      const stepCircles = container.querySelectorAll('.rounded-full.w-8.h-8');
      expect(stepCircles.length).toBe(3);
    });

    it('should highlight current step', () => {
      const business = createMockBusiness();

      const { container } = render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      const activeStep = container.querySelector('.bg-blue-600');
      expect(activeStep).toBeInTheDocument();
    });

    it('should show completed steps with checkmark', async () => {
      const business = createMockBusiness();

      const { container } = render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      // Move to next step
      const getStartedButton = screen.getByRole('button', { name: /get started/i });
      fireEvent.click(getStartedButton);

      // First step should show green background after navigation
      await waitFor(() => {
        const completedStep = container.querySelector('.bg-green-500');
        expect(completedStep).toBeTruthy();
      });
    });
  });

  describe('Welcome Step', () => {
    it('should render welcome step by default', () => {
      const business = createMockBusiness({ name: 'Test Business' });

      render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      expect(screen.getByText(/welcome to test business/i)).toBeInTheDocument();
    });

    it('should render sparkles icon', () => {
      const business = createMockBusiness();

      const { container } = render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      const iconCircle = container.querySelector('.bg-gradient-to-br.from-blue-500');
      expect(iconCircle).toBeInTheDocument();
    });

    it('should show features list', () => {
      const business = createMockBusiness();

      render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      expect(screen.getByText(/connect to stripe/i)).toBeInTheDocument();
      expect(screen.getByText(/automatic payouts/i)).toBeInTheDocument();
      expect(screen.getByText(/pci compliance/i)).toBeInTheDocument();
    });

    it('should render Get Started button', () => {
      const business = createMockBusiness();

      render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      const button = screen.getByRole('button', { name: /get started/i });
      expect(button).toBeInTheDocument();
      expect(button).toHaveClass('bg-blue-600');
    });

    it('should render Skip button', () => {
      const business = createMockBusiness();

      render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      // Look for the skip button with exact text (not the close button with title)
      const skipButtons = screen.getAllByRole('button', { name: /skip for now/i });
      expect(skipButtons.length).toBeGreaterThan(0);
    });

    it('should advance to stripe step on Get Started click', () => {
      const business = createMockBusiness();

      render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      const getStartedButton = screen.getByRole('button', { name: /get started/i });
      fireEvent.click(getStartedButton);

      expect(screen.getByText(/connect stripe/i)).toBeInTheDocument();
    });
  });

  describe('Stripe Connect Step', () => {
    beforeEach(() => {
      // Start at Stripe step
      const business = createMockBusiness();
      render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );
      const getStartedButton = screen.getByRole('button', { name: /get started/i });
      fireEvent.click(getStartedButton);
    });

    it('should render Stripe step after welcome', () => {
      expect(screen.getByText(/connect stripe/i)).toBeInTheDocument();
    });

    it('should show loading while checking status', () => {
      mockUsePaymentConfig.mockReturnValue({
        data: undefined,
        isLoading: true,
        refetch: mockRefetch,
      });

      const business = createMockBusiness();
      render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      // Navigate to stripe step
      fireEvent.click(screen.getByRole('button', { name: /get started/i }));

      expect(screen.getByText(/checking status/i)).toBeInTheDocument();
    });

    it('should render ConnectOnboardingEmbed when not connected', () => {
      expect(screen.getByTestId('connect-embed')).toBeInTheDocument();
    });

    it('should show success message when already connected', () => {
      mockUsePaymentConfig.mockReturnValue({
        data: {
          connect_account: {
            status: 'active',
            charges_enabled: true,
          },
        },
        isLoading: false,
        refetch: mockRefetch,
      });

      const business = createMockBusiness();
      render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      fireEvent.click(screen.getByRole('button', { name: /get started/i }));

      // Component auto-advances to complete step when already connected
      expect(screen.getByText(/you're all set!/i)).toBeInTheDocument();
    });

    it('should render Do This Later button', () => {
      expect(screen.getByRole('button', { name: /do this later/i })).toBeInTheDocument();
    });

    it('should handle embedded onboarding completion', async () => {
      const completeButton = screen.getByText('Complete Embed');
      fireEvent.click(completeButton);

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

    it('should handle embedded onboarding error', () => {
      const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});

      const errorButton = screen.getByText('Trigger Error');
      fireEvent.click(errorButton);

      expect(consoleErrorSpy).toHaveBeenCalledWith('Embedded onboarding error:', 'Test error');
      consoleErrorSpy.mockRestore();
    });
  });

  describe('Complete Step', () => {
    it('should render complete step when Stripe is connected', () => {
      mockUsePaymentConfig.mockReturnValue({
        data: {
          connect_account: {
            status: 'active',
            charges_enabled: true,
          },
        },
        isLoading: false,
        refetch: mockRefetch,
      });

      const business = createMockBusiness();
      render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      // Navigate to stripe step - will auto-advance to complete since connected
      fireEvent.click(screen.getByRole('button', { name: /get started/i }));

      expect(screen.getByText(/you're all set!/i)).toBeInTheDocument();
    });

    it('should show completion checklist', () => {
      mockUsePaymentConfig.mockReturnValue({
        data: {
          connect_account: {
            status: 'active',
            charges_enabled: true,
          },
        },
        isLoading: false,
        refetch: mockRefetch,
      });

      const business = createMockBusiness();
      render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      fireEvent.click(screen.getByRole('button', { name: /get started/i }));

      expect(screen.getByText(/account created/i)).toBeInTheDocument();
      expect(screen.getByText(/stripe configured/i)).toBeInTheDocument();
      expect(screen.getByText(/ready for payments/i)).toBeInTheDocument();
    });

    it('should render Go to Dashboard button', () => {
      mockUsePaymentConfig.mockReturnValue({
        data: {
          connect_account: {
            status: 'active',
            charges_enabled: true,
          },
        },
        isLoading: false,
        refetch: mockRefetch,
      });

      const business = createMockBusiness();
      render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      fireEvent.click(screen.getByRole('button', { name: /get started/i }));

      expect(screen.getByRole('button', { name: /go to dashboard/i })).toBeInTheDocument();
    });

    it('should call onComplete when dashboard button clicked', async () => {
      mockMutateAsync.mockResolvedValue({});
      mockUsePaymentConfig.mockReturnValue({
        data: {
          connect_account: {
            status: 'active',
            charges_enabled: true,
          },
        },
        isLoading: false,
        refetch: mockRefetch,
      });

      const business = createMockBusiness();
      render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      fireEvent.click(screen.getByRole('button', { name: /get started/i }));

      const dashboardButton = screen.getByRole('button', { name: /go to dashboard/i });
      fireEvent.click(dashboardButton);

      await waitFor(() => {
        expect(mockMutateAsync).toHaveBeenCalledWith({ initialSetupComplete: true });
        expect(mockOnComplete).toHaveBeenCalled();
      });
    });
  });

  describe('Skip Functionality', () => {
    it('should call onSkip when skip button clicked on welcome', async () => {
      mockMutateAsync.mockResolvedValue({});
      const business = createMockBusiness();

      render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
          onSkip={mockOnSkip}
        />,
        { wrapper: createWrapper() }
      );

      // Find the text-based skip button (not the X close button)
      const skipButtons = screen.getAllByRole('button', { name: /skip for now/i });
      const skipButton = skipButtons.find(btn => btn.textContent?.includes('Skip for now'));
      if (skipButton) {
        fireEvent.click(skipButton);

        await waitFor(() => {
          expect(mockMutateAsync).toHaveBeenCalledWith({ initialSetupComplete: true });
          expect(mockOnSkip).toHaveBeenCalled();
        });
      }
    });

    it('should call onComplete when no onSkip provided', async () => {
      mockMutateAsync.mockResolvedValue({});
      const business = createMockBusiness();

      render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      const skipButtons = screen.getAllByRole('button', { name: /skip for now/i });
      const skipButton = skipButtons.find(btn => btn.textContent?.includes('Skip for now'));
      if (skipButton) {
        fireEvent.click(skipButton);

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

    it('should update business setup complete flag on skip', async () => {
      mockMutateAsync.mockResolvedValue({});
      const business = createMockBusiness();

      render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      const skipButtons = screen.getAllByRole('button', { name: /skip for now/i });
      const skipButton = skipButtons.find(btn => btn.textContent?.includes('Skip for now'));
      if (skipButton) {
        fireEvent.click(skipButton);

        await waitFor(() => {
          expect(mockMutateAsync).toHaveBeenCalledWith({ initialSetupComplete: true });
        });
      }
    });

    it('should close wizard when X button clicked', async () => {
      mockMutateAsync.mockResolvedValue({});
      const business = createMockBusiness();

      const { container } = render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      // Find X button (close button)
      const closeButtons = screen.getAllByRole('button');
      const xButton = closeButtons.find(btn => btn.querySelector('svg') && !btn.textContent?.trim());

      if (xButton) {
        fireEvent.click(xButton);

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

  describe('Auto-advance on Stripe Connection', () => {
    it('should auto-advance to complete when Stripe connects', async () => {
      const business = createMockBusiness();

      // Start not connected
      mockUsePaymentConfig.mockReturnValue({
        data: {
          connect_account: null,
        },
        isLoading: false,
        refetch: mockRefetch,
      });

      const { rerender } = render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      // Navigate to stripe step
      fireEvent.click(screen.getByRole('button', { name: /get started/i }));

      // Simulate Stripe connection
      mockUsePaymentConfig.mockReturnValue({
        data: {
          connect_account: {
            status: 'active',
            charges_enabled: true,
          },
        },
        isLoading: false,
        refetch: mockRefetch,
      });

      rerender(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />
      );

      await waitFor(() => {
        expect(screen.getByText(/you're all set!/i)).toBeInTheDocument();
      });
    });
  });

  describe('URL Parameter Handling', () => {
    it('should handle connect=complete query parameter', () => {
      mockSearchParams.set('connect', 'complete');

      const business = createMockBusiness();
      render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      expect(mockRefetch).toHaveBeenCalled();
      expect(mockSetSearchParams).toHaveBeenCalledWith({});
    });

    it('should handle connect=refresh query parameter', () => {
      mockSearchParams.set('connect', 'refresh');

      const business = createMockBusiness();
      render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      expect(mockRefetch).toHaveBeenCalled();
      expect(mockSetSearchParams).toHaveBeenCalledWith({});
    });
  });

  describe('Loading States', () => {
    it('should disable dashboard button while updating', () => {
      mockUseUpdateBusiness.mockReturnValue({
        mutateAsync: mockMutateAsync,
        isPending: true,
      });

      mockUsePaymentConfig.mockReturnValue({
        data: {
          connect_account: {
            status: 'active',
            charges_enabled: true,
          },
        },
        isLoading: false,
        refetch: mockRefetch,
      });

      const business = createMockBusiness();
      render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      fireEvent.click(screen.getByRole('button', { name: /get started/i }));

      // Dashboard button should be disabled while updating
      const buttons = screen.getAllByRole('button');
      const dashboardButton = buttons.find(btn => btn.textContent?.includes('Dashboard') || btn.querySelector('.animate-spin'));
      if (dashboardButton) {
        expect(dashboardButton).toBeDisabled();
      }
    });
  });

  describe('Accessibility', () => {
    it('should have proper modal structure', () => {
      const business = createMockBusiness();

      const { container } = render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      // Modal overlay with fixed positioning
      const modalOverlay = container.querySelector('.fixed.z-50');
      expect(modalOverlay).toBeInTheDocument();
    });

    it('should have semantic headings', () => {
      const business = createMockBusiness();

      render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      expect(screen.getByRole('heading', { level: 2 })).toBeInTheDocument();
    });

    it('should have accessible buttons', () => {
      const business = createMockBusiness();

      render(
        <OnboardingWizard
          business={business}
          onComplete={mockOnComplete}
        />,
        { wrapper: createWrapper() }
      );

      const buttons = screen.getAllByRole('button');
      expect(buttons.length).toBeGreaterThan(0);
    });
  });
});
