import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';

vi.mock('framer-motion', () => ({
  motion: {
    div: ({ children, ...props }: any) => <div {...props}>{children}</div>,
    button: ({ children, ...props }: any) => <button {...props}>{children}</button>,
  },
}));

vi.mock('canvas-confetti', () => ({
  default: vi.fn(),
}));

describe('PaymentResult', () => {
  let PaymentResult: typeof import('../../components/PaymentResult').PaymentResult;
  let mockConfetti: ReturnType<typeof vi.fn>;

  beforeEach(async () => {
    vi.clearAllMocks();
    vi.resetModules();
    vi.useFakeTimers();

    const confettiModule = await import('canvas-confetti');
    mockConfetti = confettiModule.default as ReturnType<typeof vi.fn>;

    const module = await import('../../components/PaymentResult');
    PaymentResult = module.PaymentResult;
  });

  afterEach(() => {
    vi.useRealTimers();
    vi.resetAllMocks();
  });

  describe('loading state', () => {
    it('shows loading spinner', () => {
      render(<PaymentResult status="loading" />);

      expect(document.querySelector('.animate-spin')).toBeInTheDocument();
      expect(screen.getByText(/Processing your payment/i)).toBeInTheDocument();
    });

    it('does not trigger confetti in loading state', () => {
      render(<PaymentResult status="loading" />);

      expect(mockConfetti).not.toHaveBeenCalled();
    });
  });

  describe('success state', () => {
    it('shows success message', () => {
      render(<PaymentResult status="success" />);

      expect(screen.getByText('Welcome to Pro!')).toBeInTheDocument();
      expect(screen.getByText(/AI powers are now unlocked/i)).toBeInTheDocument();
    });

    it('shows generation count badge', () => {
      render(<PaymentResult status="success" />);

      expect(screen.getByText('250 AI generations ready to use')).toBeInTheDocument();
    });

    it('shows "Start Creating" button', () => {
      render(<PaymentResult status="success" />);

      expect(screen.getByText('Start Creating')).toBeInTheDocument();
    });

    it('calls onBack when "Start Creating" is clicked', () => {
      const mockOnBack = vi.fn();
      render(<PaymentResult status="success" onBack={mockOnBack} />);

      fireEvent.click(screen.getByText('Start Creating'));

      expect(mockOnBack).toHaveBeenCalled();
    });

    it('triggers confetti animation on mount', async () => {
      render(<PaymentResult status="success" />);

      vi.advanceTimersByTime(100);

      expect(mockConfetti).toHaveBeenCalled();
    });

    it('confetti uses correct colors', async () => {
      render(<PaymentResult status="success" />);

      vi.advanceTimersByTime(100);

      expect(mockConfetti).toHaveBeenCalledWith(
        expect.objectContaining({
          colors: ['#8B5CF6', '#6366F1', '#EC4899', '#F59E0B'],
        })
      );
    });

    it('only triggers confetti once', async () => {
      const { rerender } = render(<PaymentResult status="success" />);

      vi.advanceTimersByTime(3100);

      const callCountAfterFirst = mockConfetti.mock.calls.length;

      rerender(<PaymentResult status="success" />);
      vi.advanceTimersByTime(3100);

      expect(mockConfetti.mock.calls.length).toBe(callCountAfterFirst);
    });
  });

  describe('cancel state', () => {
    it('shows cancel message', () => {
      render(<PaymentResult status="cancel" />);

      expect(screen.getByText('Payment Cancelled')).toBeInTheDocument();
      expect(screen.getByText(/No worries/i)).toBeInTheDocument();
    });

    it('shows "Go Back" button', () => {
      render(<PaymentResult status="cancel" />);

      expect(screen.getByText('Go Back')).toBeInTheDocument();
    });

    it('calls onBack when "Go Back" is clicked', () => {
      const mockOnBack = vi.fn();
      render(<PaymentResult status="cancel" onBack={mockOnBack} />);

      fireEvent.click(screen.getByText('Go Back'));

      expect(mockOnBack).toHaveBeenCalled();
    });

    it('does not show generation count badge', () => {
      render(<PaymentResult status="cancel" />);

      expect(screen.queryByText(/250 AI generations/i)).not.toBeInTheDocument();
    });

    it('does not trigger confetti', () => {
      render(<PaymentResult status="cancel" />);

      vi.advanceTimersByTime(3100);

      expect(mockConfetti).not.toHaveBeenCalled();
    });
  });

  describe('UI elements', () => {
    it('renders PartyPopper icon for success', () => {
      render(<PaymentResult status="success" />);

      const successCard = screen.getByText('Welcome to Pro!').closest('div');
      expect(successCard).toBeInTheDocument();
    });

    it('renders XCircle icon for cancel', () => {
      render(<PaymentResult status="cancel" />);

      const cancelCard = screen.getByText('Payment Cancelled').closest('div');
      expect(cancelCard).toBeInTheDocument();
    });

    it('has green gradient background for success', () => {
      render(<PaymentResult status="success" />);

      const gradientBg = document.querySelector('.from-green-50');
      expect(gradientBg).toBeInTheDocument();
    });

    it('does not have green gradient for cancel', () => {
      render(<PaymentResult status="cancel" />);

      const gradientBg = document.querySelector('.from-green-50');
      expect(gradientBg).not.toBeInTheDocument();
    });
  });

  describe('button styling', () => {
    it('success button has dark styling', () => {
      render(<PaymentResult status="success" />);

      const button = screen.getByText('Start Creating').closest('button');
      expect(button?.className).toContain('bg-gray-900');
    });

    it('cancel button has theme primary styling', () => {
      render(<PaymentResult status="cancel" />);

      const button = screen.getByText('Go Back').closest('button');
      expect(button?.className).toContain('bg-theme-primary');
    });
  });

  describe('without onBack callback', () => {
    it('renders buttons without errors when onBack is undefined', () => {
      render(<PaymentResult status="success" />);

      const button = screen.getByText('Start Creating');
      expect(button).toBeInTheDocument();

      fireEvent.click(button);
    });
  });
});
