import { Sentiment } from '../../common';
import { mockMatchMedia, render, screen } from '../../test-utils';
import { ActionPrompt, ActionPromptProps } from './ActionPrompt';
import { userEvent } from '@testing-library/user-event';

mockMatchMedia();

describe('ActionPrompt', () => {
  const defaultProps: ActionPromptProps = {
    title: 'Test Title',
    action: {
      label: 'Primary Action',
      onClick: jest.fn(),
    },
  };

  beforeEach(() => {
    jest.clearAllMocks();
  });

  describe('Basic rendering', () => {
    it('renders title', () => {
      render(<ActionPrompt {...defaultProps} />);
      expect(screen.getByText('Test Title')).toBeInTheDocument();
    });

    it('renders description when provided', () => {
      render(<ActionPrompt {...defaultProps} description="Test description" />);
      expect(screen.getByText('Test description')).toBeInTheDocument();
    });
  });

  [
    { sentiment: 'negative' as const, statusIconLabel: 'Error:' },
    { sentiment: 'warning' as const, statusIconLabel: 'Warning:' },
    { sentiment: 'neutral' as const, statusIconLabel: 'Information:' },
    { sentiment: 'success' as const, statusIconLabel: 'Success:' },
    { sentiment: 'proposition' as const, statusIconLabel: '' },
  ].forEach(({ sentiment, statusIconLabel }) => {
    describe(sentiment, () => {
      if (statusIconLabel) {
        it('should render StatusIcon', () => {
          render(<ActionPrompt {...defaultProps} sentiment={sentiment} />);
          expect(screen.getByLabelText(statusIconLabel)).toBeInTheDocument();
        });
      }
    });
  });

  describe('Actions', () => {
    it('renders primary action button with correct label', () => {
      render(<ActionPrompt {...defaultProps} />);
      expect(screen.getByText('Primary Action')).toBeInTheDocument();
    });

    it('calls primary action onClick when clicked', async () => {
      const onClick = jest.fn();
      const user = userEvent.setup();
      render(
        <ActionPrompt {...defaultProps} action={{ label: 'Primary Action', onClick }} />,
      );
      const button = screen.getByRole('button', { name: 'Primary Action' });
      await user.click(button);
      expect(onClick).toHaveBeenCalledTimes(1);
    });

    it('renders primary action as link when href is provided', () => {
      render(
        <ActionPrompt
          {...defaultProps}
          action={{ label: 'Primary Action', href: '/test-url' }}
        />,
      );
      const link = screen.getByRole('link', { name: 'Primary Action' });
      expect(link).toHaveAttribute('href', '/test-url');
    });

    it('renders secondary action when provided', () => {
      render(
        <ActionPrompt
          {...defaultProps}
          actionSecondary={{ label: 'Secondary Action', onClick: jest.fn() }}
        />,
      );
      expect(screen.getByText('Secondary Action')).toBeInTheDocument();
    });

    it('calls secondary action onClick when clicked', async () => {
      const onClick = jest.fn();
      const user = userEvent.setup();
      render(
        <ActionPrompt {...defaultProps} actionSecondary={{ label: 'Secondary Action', onClick }} />,
      );
      const button = screen.getByRole('button', { name: 'Secondary Action' });
      await user.click(button);
      expect(onClick).toHaveBeenCalledTimes(1);
    });

    it('renders secondary action as link when href is provided', () => {
      render(
        <ActionPrompt
          {...defaultProps}
          actionSecondary={{ label: 'Secondary Action', href: '/secondary-url' }}
        />,
      );
      const link = screen.getByRole('link', { name: 'Secondary Action' });
      expect(link).toHaveAttribute('href', '/secondary-url');
    });
  });

  describe('Media', () => {
    describe('Image media', () => {
      it('renders custom image when imgSrc is provided', () => {
        render(
          <ActionPrompt
            {...defaultProps}
            media={{ imgSrc: '/test-image.jpg', 'aria-label': 'Test image' }}
          />,
        );

        const img = screen.getByRole('img', { name: 'Test image' });

        expect(img).toBeInTheDocument();
        expect(img).toHaveAttribute('src', '/test-image.jpg');
      });

      it('renders image with empty alt when aria-label is not provided', () => {
        const { container } = render(
          <ActionPrompt {...defaultProps} media={{ imgSrc: '/test-image.jpg' }} />,
        );
        const img = container.querySelector('img[src="/test-image.jpg"]');
        expect(img).toHaveAttribute('alt', '');
      });
    });

    describe('Avatar media', () => {
      it('renders avatar with image', () => {
        const { container } = render(
          <ActionPrompt {...defaultProps} media={{ avatar: { imgSrc: '/avatar.jpg' } }} />,
        );
        const img = container.querySelector('img[src="/avatar.jpg"]');
        expect(img).toBeInTheDocument();
        expect(img).toHaveAttribute('src', '/avatar.jpg');
      });

      it('renders avatar with profile name', () => {
        render(<ActionPrompt {...defaultProps} media={{ avatar: { profileName: 'John Doe' } }} />);
        expect(screen.getByText('JD')).toBeInTheDocument();
      });

      it('renders avatar with custom asset', () => {
        render(
          <ActionPrompt
            {...defaultProps}
            media={{ avatar: { asset: <span data-testid="custom-icon">Icon</span> } }}
          />,
        );

        expect(screen.getByTestId('custom-icon')).toBeInTheDocument();
      });

      it('renders avatar with badge', () => {
        render(
          <ActionPrompt
            {...defaultProps}
            media={{ avatar: { profileType: 'BUSINESS', badge: { flagCode: 'GB' } } }}
          />,
        );

        expect(screen.getByText('Test Title')).toBeInTheDocument();
      });

      it('applies status badge for non-proposition sentiment when no badge is provided', () => {
        render(
          <ActionPrompt
            {...defaultProps}
            sentiment="success"
            media={{ avatar: { profileType: 'PERSONAL' } }}
          />,
        );

        expect(screen.getByText('Test Title')).toBeInTheDocument();
      });

      it('renders avatar for proposition sentiment when no badge is provided', () => {
        render(
          <ActionPrompt
            {...defaultProps}
            sentiment="proposition"
            media={{ avatar: { profileType: 'PERSONAL' } }}
          />,
        );

        expect(screen.getByText('Test Title')).toBeInTheDocument();
      });
    });

    describe('Default media', () => {
      it('renders GiftBox for proposition sentiment with no media', () => {
        render(<ActionPrompt {...defaultProps} sentiment="proposition" />);
        expect(screen.getByTestId('gift-box-icon')).toBeInTheDocument();
      });

      it('renders StatusIcon for non-proposition sentiment with no media', () => {
        render(<ActionPrompt {...defaultProps} sentiment="success" />);
        expect(screen.getByText('Test Title')).toBeInTheDocument();
      });
    });
  });

  describe('Two actions styling', () => {
    it('applies two actions class when secondary action is provided', () => {
      render(
        <ActionPrompt
          {...defaultProps}
          actionSecondary={{ label: 'Secondary', onClick: jest.fn() }}
          data-testid="prompt"
        />,
      );

      expect(screen.getByTestId('prompt')).toHaveClass('wds-action-prompt--with-two-actions');
    });

    it('does not apply two actions class when only primary action is provided', () => {
      render(<ActionPrompt {...defaultProps} data-testid="prompt" />);
      expect(screen.getByTestId('prompt')).not.toHaveClass('wds-action-prompt--with-two-actions');
    });
  });

  describe('Responsive behavior', () => {
    it('renders buttons as block on mobile', () => {
      // Mock mobile viewport
      const mockMatchMediaFn = window.matchMedia as jest.Mock;
      mockMatchMediaFn.mockImplementation((query: string) => ({
        matches: query === '(max-width: 768px)',
        media: query,
        onchange: null,
        addListener: jest.fn(),
        removeListener: jest.fn(),
        addEventListener: jest.fn(),
        removeEventListener: jest.fn(),
        dispatchEvent: jest.fn(),
      }));

      render(
        <ActionPrompt
          {...defaultProps}
          actionSecondary={{ label: 'Secondary', onClick: jest.fn() }}
        />,
      );

      expect(screen.getByText('Primary Action')).toBeInTheDocument();
      expect(screen.getByText('Secondary')).toBeInTheDocument();
    });
  });
});
