/**
 * Unit tests for TrialBanner component
 *
 * Tests the trial status banner that appears at the top of the business layout.
 * Covers:
 * - Rendering with different days remaining
 * - Urgent state (3 days or less)
 * - Upgrade button navigation
 * - Dismiss functionality
 * - Hidden states (dismissed, not active, no days left)
 * - Trial end date formatting
 */

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent, within } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import TrialBanner from '../TrialBanner';
import { Business } from '../../types';

// Mock react-router-dom's useNavigate
const mockNavigate = vi.fn();
vi.mock('react-router-dom', async () => {
  const actual = await vi.importActual('react-router-dom');
  return {
    ...actual,
    useNavigate: () => mockNavigate,
  };
});

// Mock i18next
vi.mock('react-i18next', () => ({
  useTranslation: () => ({
    t: (key: string, params?: Record<string, unknown>) => {
      // Simulate translation behavior
      const translations: Record<string, string> = {
        'trial.banner.title': 'Trial Active',
        'trial.banner.daysLeft': `${params?.days} days left in trial`,
        'trial.banner.expiresOn': `Trial expires on ${params?.date}`,
        'trial.banner.upgradeNow': 'Upgrade Now',
        'trial.banner.dismiss': 'Dismiss',
      };
      return translations[key] || key;
    },
  }),
}));

// Test data factory for Business objects
const createMockBusiness = (overrides?: Partial<Business>): Business => ({
  id: '1',
  name: 'Test Business',
  subdomain: 'testbiz',
  primaryColor: '#3B82F6',
  secondaryColor: '#1E40AF',
  whitelabelEnabled: false,
  paymentsEnabled: true,
  requirePaymentMethodToBook: false,
  cancellationWindowHours: 24,
  lateCancellationFeePercent: 50,
  isTrialActive: true,
  daysLeftInTrial: 10,
  trialEnd: '2025-12-17T23:59:59Z',
  ...overrides,
});

// Wrapper component that provides router context
const renderWithRouter = (ui: React.ReactElement) => {
  return render(<BrowserRouter>{ui}</BrowserRouter>);
};

describe('TrialBanner', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('Rendering', () => {
    it('should render banner with trial information when trial is active', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 10,
        trialEnd: '2025-12-17T23:59:59Z',
      });

      renderWithRouter(<TrialBanner business={business} />);

      expect(screen.getByText(/trial active/i)).toBeInTheDocument();
      expect(screen.getByText(/10 days left in trial/i)).toBeInTheDocument();
      expect(screen.getByRole('button', { name: /upgrade now/i })).toBeInTheDocument();
    });

    it('should display the trial end date', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 5,
        trialEnd: '2025-12-17T00:00:00Z',
      });

      renderWithRouter(<TrialBanner business={business} />);

      // Check that the date is displayed (format may vary by locale)
      expect(screen.getByText(/trial expires on/i)).toBeInTheDocument();
    });

    it('should render Sparkles icon when more than 3 days left', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 7,
      });

      const { container } = renderWithRouter(<TrialBanner business={business} />);

      // The Sparkles icon should be rendered (not the Clock icon)
      // Check for the non-urgent styling
      const banner = container.querySelector('.bg-gradient-to-r.from-blue-600');
      expect(banner).toBeInTheDocument();
    });

    it('should render Clock icon with pulse animation when 3 days or less left', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 3,
      });

      const { container } = renderWithRouter(<TrialBanner business={business} />);

      // Check for urgent styling
      const banner = container.querySelector('.bg-gradient-to-r.from-red-500');
      expect(banner).toBeInTheDocument();

      // Check for pulse animation on the icon
      const pulsingIcon = container.querySelector('.animate-pulse');
      expect(pulsingIcon).toBeInTheDocument();
    });

    it('should render Upgrade Now button with arrow icon', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 10,
      });

      renderWithRouter(<TrialBanner business={business} />);

      const upgradeButton = screen.getByRole('button', { name: /upgrade now/i });
      expect(upgradeButton).toBeInTheDocument();
      expect(upgradeButton).toHaveClass('bg-white', 'text-blue-600');
    });

    it('should render dismiss button with aria-label', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 10,
      });

      renderWithRouter(<TrialBanner business={business} />);

      const dismissButton = screen.getByRole('button', { name: /dismiss/i });
      expect(dismissButton).toBeInTheDocument();
      expect(dismissButton).toHaveAttribute('aria-label', 'Dismiss');
    });
  });

  describe('Urgent State (3 days or less)', () => {
    it('should apply urgent styling when 3 days left', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 3,
      });

      const { container } = renderWithRouter(<TrialBanner business={business} />);

      const banner = container.querySelector('.bg-gradient-to-r.from-red-500.to-orange-500');
      expect(banner).toBeInTheDocument();
    });

    it('should apply urgent styling when 2 days left', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 2,
      });

      const { container } = renderWithRouter(<TrialBanner business={business} />);

      const banner = container.querySelector('.bg-gradient-to-r.from-red-500.to-orange-500');
      expect(banner).toBeInTheDocument();
    });

    it('should apply urgent styling when 1 day left', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 1,
      });

      const { container } = renderWithRouter(<TrialBanner business={business} />);

      expect(screen.getByText(/1 days left in trial/i)).toBeInTheDocument();
      const banner = container.querySelector('.bg-gradient-to-r.from-red-500.to-orange-500');
      expect(banner).toBeInTheDocument();
    });

    it('should NOT apply urgent styling when 4 days left', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 4,
      });

      const { container } = renderWithRouter(<TrialBanner business={business} />);

      const banner = container.querySelector('.bg-gradient-to-r.from-blue-600.to-blue-500');
      expect(banner).toBeInTheDocument();
      expect(container.querySelector('.from-red-500')).not.toBeInTheDocument();
    });
  });

  describe('User Interactions', () => {
    it('should navigate to /upgrade when Upgrade Now button is clicked', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 10,
      });

      renderWithRouter(<TrialBanner business={business} />);

      const upgradeButton = screen.getByRole('button', { name: /upgrade now/i });
      fireEvent.click(upgradeButton);

      expect(mockNavigate).toHaveBeenCalledWith('/upgrade');
      expect(mockNavigate).toHaveBeenCalledTimes(1);
    });

    it('should hide banner when dismiss button is clicked', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 10,
      });

      renderWithRouter(<TrialBanner business={business} />);

      // Banner should be visible initially
      expect(screen.getByText(/trial active/i)).toBeInTheDocument();

      // Click dismiss button
      const dismissButton = screen.getByRole('button', { name: /dismiss/i });
      fireEvent.click(dismissButton);

      // Banner should be hidden
      expect(screen.queryByText(/trial active/i)).not.toBeInTheDocument();
    });

    it('should keep banner hidden after dismissing even when multiple clicks', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 10,
      });

      renderWithRouter(<TrialBanner business={business} />);

      const dismissButton = screen.getByRole('button', { name: /dismiss/i });
      fireEvent.click(dismissButton);

      // Banner should remain hidden
      expect(screen.queryByText(/trial active/i)).not.toBeInTheDocument();
    });
  });

  describe('Hidden States', () => {
    it('should not render when trial is not active', () => {
      const business = createMockBusiness({
        isTrialActive: false,
        daysLeftInTrial: 10,
      });

      renderWithRouter(<TrialBanner business={business} />);

      expect(screen.queryByText(/trial active/i)).not.toBeInTheDocument();
    });

    it('should not render when daysLeftInTrial is undefined', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: undefined,
      });

      renderWithRouter(<TrialBanner business={business} />);

      expect(screen.queryByText(/trial active/i)).not.toBeInTheDocument();
    });

    it('should not render when daysLeftInTrial is 0', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 0,
      });

      renderWithRouter(<TrialBanner business={business} />);

      expect(screen.queryByText(/trial active/i)).not.toBeInTheDocument();
    });

    it('should not render when daysLeftInTrial is null', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: null as unknown as number,
      });

      renderWithRouter(<TrialBanner business={business} />);

      expect(screen.queryByText(/trial active/i)).not.toBeInTheDocument();
    });

    it('should not render when already dismissed', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 10,
      });

      renderWithRouter(<TrialBanner business={business} />);

      // Dismiss the banner
      const dismissButton = screen.getByRole('button', { name: /dismiss/i });
      fireEvent.click(dismissButton);

      // Banner should not be visible
      expect(screen.queryByText(/trial active/i)).not.toBeInTheDocument();
    });
  });

  describe('Edge Cases', () => {
    it('should handle missing trialEnd date gracefully', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 5,
        trialEnd: undefined,
      });

      renderWithRouter(<TrialBanner business={business} />);

      // Banner should still render
      expect(screen.getByText(/trial active/i)).toBeInTheDocument();
      expect(screen.getByText(/5 days left in trial/i)).toBeInTheDocument();
    });

    it('should handle invalid trialEnd date gracefully', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 5,
        trialEnd: 'invalid-date',
      });

      renderWithRouter(<TrialBanner business={business} />);

      // Banner should still render despite invalid date
      expect(screen.getByText(/trial active/i)).toBeInTheDocument();
    });

    it('should display correct styling for boundary case of exactly 3 days', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 3,
      });

      const { container } = renderWithRouter(<TrialBanner business={business} />);

      // Should use urgent styling at exactly 3 days
      const banner = container.querySelector('.bg-gradient-to-r.from-red-500');
      expect(banner).toBeInTheDocument();
    });

    it('should handle very large number of days remaining', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 999,
      });

      renderWithRouter(<TrialBanner business={business} />);

      expect(screen.getByText(/999 days left in trial/i)).toBeInTheDocument();
      // Should use non-urgent styling
      const { container } = render(<TrialBanner business={business} />, { wrapper: BrowserRouter });
      const banner = container.querySelector('.bg-gradient-to-r.from-blue-600');
      expect(banner).toBeInTheDocument();
    });
  });

  describe('Accessibility', () => {
    it('should have proper button roles and labels', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 10,
      });

      renderWithRouter(<TrialBanner business={business} />);

      const upgradeButton = screen.getByRole('button', { name: /upgrade now/i });
      const dismissButton = screen.getByRole('button', { name: /dismiss/i });

      expect(upgradeButton).toBeInTheDocument();
      expect(dismissButton).toBeInTheDocument();
      expect(dismissButton).toHaveAttribute('aria-label');
    });

    it('should have readable text content for screen readers', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 7,
        trialEnd: '2025-12-24T23:59:59Z',
      });

      renderWithRouter(<TrialBanner business={business} />);

      // All important text should be accessible
      expect(screen.getByText(/trial active/i)).toBeInTheDocument();
      expect(screen.getByText(/7 days left in trial/i)).toBeInTheDocument();
      expect(screen.getByText(/trial expires on/i)).toBeInTheDocument();
    });
  });

  describe('Responsive Behavior', () => {
    it('should render trial end date with hidden class for small screens', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 10,
        trialEnd: '2025-12-17T23:59:59Z',
      });

      const { container } = renderWithRouter(<TrialBanner business={business} />);

      // The trial end date paragraph should have 'hidden sm:block' classes
      const endDateElement = container.querySelector('.hidden.sm\\:block');
      expect(endDateElement).toBeInTheDocument();
    });

    it('should render all key elements in the banner', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 10,
      });

      const { container } = renderWithRouter(<TrialBanner business={business} />);

      // Icon container
      const iconContainer = container.querySelector('.p-2.rounded-full');
      expect(iconContainer).toBeInTheDocument();

      // Buttons container
      const buttonsContainer = screen.getByRole('button', { name: /upgrade now/i }).parentElement;
      expect(buttonsContainer).toBeInTheDocument();
    });
  });

  describe('Component Integration', () => {
    it('should work with different business configurations', () => {
      const businesses = [
        createMockBusiness({ daysLeftInTrial: 1, isTrialActive: true }),
        createMockBusiness({ daysLeftInTrial: 7, isTrialActive: true }),
        createMockBusiness({ daysLeftInTrial: 14, isTrialActive: true }),
      ];

      businesses.forEach((business) => {
        const { unmount } = renderWithRouter(<TrialBanner business={business} />);
        expect(screen.getByText(/trial active/i)).toBeInTheDocument();
        unmount();
      });
    });

    it('should maintain state across re-renders when not dismissed', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 10,
      });

      const { rerender } = renderWithRouter(<TrialBanner business={business} />);

      expect(screen.getByText(/trial active/i)).toBeInTheDocument();

      // Re-render with updated days
      const updatedBusiness = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 9,
      });

      rerender(
        <BrowserRouter>
          <TrialBanner business={updatedBusiness} />
        </BrowserRouter>
      );

      expect(screen.getByText(/9 days left in trial/i)).toBeInTheDocument();
    });

    it('should reset dismissed state on component unmount and remount', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 10,
      });

      const { unmount } = renderWithRouter(<TrialBanner business={business} />);

      // Dismiss the banner
      const dismissButton = screen.getByRole('button', { name: /dismiss/i });
      fireEvent.click(dismissButton);

      expect(screen.queryByText(/trial active/i)).not.toBeInTheDocument();

      // Unmount and remount
      unmount();
      renderWithRouter(<TrialBanner business={business} />);

      // Banner should reappear (dismissed state is not persisted)
      expect(screen.getByText(/trial active/i)).toBeInTheDocument();
    });
  });

  describe('Additional Edge Cases', () => {
    it('should handle negative days left gracefully', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: -5,
      });

      renderWithRouter(<TrialBanner business={business} />);

      // Should still render (backend shouldn't send this, but defensive coding)
      expect(screen.getByText(/-5 days left in trial/i)).toBeInTheDocument();
    });

    it('should handle fractional days by rounding', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 5.7 as number,
      });

      renderWithRouter(<TrialBanner business={business} />);

      // Should display with the value received
      expect(screen.getByText(/5.7 days left in trial/i)).toBeInTheDocument();
    });

    it('should transition from urgent to non-urgent styling on update', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 3,
      });

      const { container, rerender } = renderWithRouter(<TrialBanner business={business} />);

      // Initially urgent
      expect(container.querySelector('.from-red-500')).toBeInTheDocument();

      // Update to non-urgent
      const updatedBusiness = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 10,
      });

      rerender(
        <BrowserRouter>
          <TrialBanner business={updatedBusiness} />
        </BrowserRouter>
      );

      // Should now be non-urgent
      expect(container.querySelector('.from-blue-600')).toBeInTheDocument();
      expect(container.querySelector('.from-red-500')).not.toBeInTheDocument();
    });

    it('should handle business without name gracefully', () => {
      const business = createMockBusiness({
        name: '',
        isTrialActive: true,
        daysLeftInTrial: 10,
      });

      renderWithRouter(<TrialBanner business={business} />);

      // Should still render the banner
      expect(screen.getByText(/trial active/i)).toBeInTheDocument();
    });

    it('should handle switching from active to inactive trial', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 5,
      });

      const { rerender } = renderWithRouter(<TrialBanner business={business} />);

      expect(screen.getByText(/trial active/i)).toBeInTheDocument();

      // Update to inactive
      const updatedBusiness = createMockBusiness({
        isTrialActive: false,
        daysLeftInTrial: 5,
      });

      rerender(
        <BrowserRouter>
          <TrialBanner business={updatedBusiness} />
        </BrowserRouter>
      );

      // Should no longer render
      expect(screen.queryByText(/trial active/i)).not.toBeInTheDocument();
    });
  });

  describe('Button Interactions', () => {
    it('should prevent multiple rapid clicks on upgrade button', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 10,
      });

      renderWithRouter(<TrialBanner business={business} />);

      const upgradeButton = screen.getByRole('button', { name: /upgrade now/i });

      // Rapid clicks
      fireEvent.click(upgradeButton);
      fireEvent.click(upgradeButton);
      fireEvent.click(upgradeButton);

      // Navigate should still only be called once per click (no debouncing in component)
      expect(mockNavigate).toHaveBeenCalledTimes(3);
    });

    it('should not interfere with other buttons after dismiss', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 10,
      });

      renderWithRouter(<TrialBanner business={business} />);

      const dismissButton = screen.getByRole('button', { name: /dismiss/i });
      fireEvent.click(dismissButton);

      // Banner is gone
      expect(screen.queryByText(/trial active/i)).not.toBeInTheDocument();

      // Upgrade button should also be gone
      expect(screen.queryByRole('button', { name: /upgrade now/i })).not.toBeInTheDocument();
    });
  });

  describe('Visual States', () => {
    it('should have shadow and proper background for visibility', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 10,
      });

      const { container } = renderWithRouter(<TrialBanner business={business} />);

      const banner = container.querySelector('.shadow-md');
      expect(banner).toBeInTheDocument();
    });

    it('should have gradient background for visual appeal', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 10,
      });

      const { container } = renderWithRouter(<TrialBanner business={business} />);

      const gradient = container.querySelector('.bg-gradient-to-r');
      expect(gradient).toBeInTheDocument();
    });

    it('should show hover states on interactive elements', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 10,
      });

      renderWithRouter(<TrialBanner business={business} />);

      const upgradeButton = screen.getByRole('button', { name: /upgrade now/i });
      expect(upgradeButton).toHaveClass('hover:bg-blue-50');
    });

    it('should have appropriate spacing and padding', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 10,
      });

      const { container } = renderWithRouter(<TrialBanner business={business} />);

      // Check for padding classes
      const contentContainer = container.querySelector('.py-3');
      expect(contentContainer).toBeInTheDocument();
    });
  });

  describe('Icon Rendering', () => {
    it('should render icons with proper size', () => {
      const business = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 10,
      });

      const { container } = renderWithRouter(<TrialBanner business={business} />);

      // Icons should have consistent size classes
      const iconContainer = container.querySelector('.rounded-full');
      expect(iconContainer).toBeInTheDocument();
    });

    it('should show different icons for urgent vs non-urgent states', () => {
      const nonUrgentBusiness = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 10,
      });

      const { container: container1, unmount } = renderWithRouter(
        <TrialBanner business={nonUrgentBusiness} />
      );

      // Non-urgent should not have pulse animation
      expect(container1.querySelector('.animate-pulse')).not.toBeInTheDocument();

      unmount();

      const urgentBusiness = createMockBusiness({
        isTrialActive: true,
        daysLeftInTrial: 2,
      });

      const { container: container2 } = renderWithRouter(
        <TrialBanner business={urgentBusiness} />
      );

      // Urgent should have pulse animation
      expect(container2.querySelector('.animate-pulse')).toBeInTheDocument();
    });
  });
});
