/**
 * Tests for MobilePushPreviewContent Component
 * 
 * Tests MobilePush preview rendering with all states, media types, carousel, and edge cases
 */

import React from 'react';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
import { injectIntl, IntlProvider } from 'react-intl';
import MobilePushPreviewContent from '../../UnifiedPreview/MobilePushPreviewContent';
import { ANDROID, IOS, MEDIA_TYPE_IMAGE, MEDIA_TYPE_VIDEO } from '../../constants';
import messages from '../../messages';

// Convert messages object to format expected by IntlProvider
const messagesForIntl = Object.keys(messages).reduce((acc, key) => {
  const message = messages[key];
  acc[message.id] = message.defaultMessage;
  return acc;
}, {});

// Wrap component with injectIntl - extract formatMessage from intl and pass to component
const ComponentToRender = injectIntl(({ intl, ...props }) => (
  <MobilePushPreviewContent {...props} formatMessage={intl.formatMessage} />
));

// Test wrapper - use IntlProvider with messages
const TestWrapper = ({ children }) => (
  <IntlProvider locale="en" messages={messagesForIntl}>
    {children}
  </IntlProvider>
);

describe('MobilePushPreviewContent', () => {
  const defaultProps = {
    content: {
      androidContent: {
        header: 'Android Header',
        bodyText: 'Android Body',
      },
      iosContent: {
        header: 'iOS Header',
        bodyText: 'iOS Body',
      },
    },
    device: ANDROID,
    isUpdating: false,
    error: null,
    // formatMessage will be injected by injectIntl
  };

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

  describe('Loading State', () => {
    it('should render loading state when isUpdating is true', () => {
      const props = {
        ...defaultProps,
        isUpdating: true,
      };

      render(
        <TestWrapper>
          <ComponentToRender {...props} />
        </TestWrapper>
      );

      expect(screen.getByText('Updating preview with the latest changes')).toBeTruthy();
    });
  });

  describe('Error State', () => {
    it('should render error state when error is present', () => {
      const props = {
        ...defaultProps,
        error: 'Failed to load preview',
      };

      render(
        <TestWrapper>
          <ComponentToRender {...props} />
        </TestWrapper>
      );

      expect(screen.getAllByText('Failed to load preview')).toHaveLength(2);
    });
  });

  describe('Content Extraction', () => {
    it('should extract Android content for ANDROID device', () => {
      const props = {
        ...defaultProps,
        device: ANDROID,
        content: {
          androidContent: {
            header: 'Android Header',
            bodyText: 'Android Body',
          },
          iosContent: {
            header: 'iOS Header',
            bodyText: 'iOS Body',
          },
        },
      };

      render(
        <TestWrapper>
          <ComponentToRender {...props} />
        </TestWrapper>
      );

      expect(screen.getByText('Android Header')).toBeTruthy();
      expect(screen.getByText('Android Body')).toBeTruthy();
    });

    it('should extract iOS content for IOS device', () => {
      const props = {
        ...defaultProps,
        device: IOS,
        content: {
          androidContent: {
            header: 'Android Header',
            bodyText: 'Android Body',
          },
          iosContent: {
            header: 'iOS Header',
            bodyText: 'iOS Body',
          },
        },
      };

      render(
        <TestWrapper>
          <ComponentToRender {...props} />
        </TestWrapper>
      );

      expect(screen.getByText('iOS Header')).toBeTruthy();
      expect(screen.getByText('iOS Body')).toBeTruthy();
    });

    it('should use direct content object as fallback', () => {
      const props = {
        ...defaultProps,
        content: {
          header: 'Direct Header',
          bodyText: 'Direct Body',
        },
      };

      render(
        <TestWrapper>
          <ComponentToRender {...props} />
        </TestWrapper>
      );

      expect(screen.getByText('Direct Header')).toBeTruthy();
      expect(screen.getByText('Direct Body')).toBeTruthy();
    });
  });

  describe('Media Content', () => {
    it('should render body image', () => {
      const props = {
        ...defaultProps,
        content: {
          androidContent: {
            header: 'Header',
            bodyText: 'Body',
            bodyImage: 'https://image.url',
          },
        },
      };

      const { container } = render(
        <TestWrapper>
          <MobilePushPreviewContent {...props} />
        </TestWrapper>
      );

      const image = container.querySelectorAll('img');
      expect(image[1]).toBeTruthy();
      expect(image[1].getAttribute('src')).toBe('https://image.url');
    });

    it('should render video when bodyVideo.videoSrc is present', () => {
      const props = {
        ...defaultProps,
        content: {
          androidContent: {
            header: 'Header',
            bodyText: 'Body',
            bodyVideo: {
              videoSrc: 'https://video.url',
              videoPreview: 'https://preview.url',
            },
          },
        },
      };

      const { container } = render(
        <TestWrapper>
          <MobilePushPreviewContent {...props} />
        </TestWrapper>
      );

      const video = container.querySelector('video');
      expect(video).toBeTruthy();
      expect(video.getAttribute('poster')).toBe('https://preview.url');
    });

    it('should render GIF when bodyGif is present', () => {
      const props = {
        ...defaultProps,
        content: {
          androidContent: {
            header: 'Header',
            bodyText: 'Body',
            bodyGif: 'https://gif.url',
          },
        },
      };

      const { container } = render(
        <TestWrapper>
          <MobilePushPreviewContent {...props} />
        </TestWrapper>
      );

      const gif = container.querySelector('img[src="https://gif.url"]');
      expect(gif).toBeTruthy();
    });

    it('should prioritize video when video, image, and GIF are all present', () => {
      const props = {
        ...defaultProps,
        content: {
          androidContent: {
            header: 'Header',
            bodyText: 'Body',
            bodyVideo: {
              videoSrc: 'https://video.url',
            },
          },
        },
      };

      const { container } = render(
        <TestWrapper>
          <MobilePushPreviewContent {...props} />
        </TestWrapper>
      );
      const video = container.querySelector('video');
      expect(video).toBeTruthy();
    });
  });

  describe('Action Buttons', () => {
    it('should render action buttons when actions are present', () => {
      const props = {
        ...defaultProps,
        content: {
          androidContent: {
            header: 'Header',
            bodyText: 'Body',
            carouselData: [],
            actions: [
              { label: 'Action 1', url: 'https://url1.com' },
              { label: 'Action 2', url: 'https://url2.com' },
            ],
          },
        },
      };

      render(
        <TestWrapper>
          <ComponentToRender {...props} />
        </TestWrapper>
      );

      expect(screen.getByText('ACTION 1')).toBeTruthy();
      expect(screen.getByText('ACTION 2')).toBeTruthy();
    });

    it('should use actionText as fallback for label', () => {
      const props = {
        ...defaultProps,
        content: {
          androidContent: {
            header: 'Header',
            bodyText: 'Body',
            carouselData: [],
            actions: [
              { actionText: 'Action Text', actionLink: 'https://url.com' },
            ],
          },
        },
      };

      render(
        <TestWrapper>
          <ComponentToRender {...props} />
        </TestWrapper>
      );

      expect(screen.getByText('ACTION TEXT')).toBeTruthy();
    });

    it('should not render actions when carouselData is present', () => {
      const props = {
        ...defaultProps,
        content: {
          androidContent: {
            header: 'Header',
            bodyText: 'Body',
            actions: [
              { label: 'Action 1' },
            ],
            carouselData: [
              { title: 'Carousel Item' },
            ],
          },
        },
      };

      render(
        <TestWrapper>
          <ComponentToRender {...props} />
        </TestWrapper>
      );

      expect(screen.queryByText('ACTION 1')).toBeNull();
    });

    it('should filter out actions without label or actionText', () => {
      const props = {
        ...defaultProps,
        content: {
          androidContent: {
            header: 'Header',
            bodyText: 'Body',
            carouselData: [],
            actions: [
              { label: 'Action 1' },
              { url: 'https://url.com' }, // No label or actionText
            ],
          },
        },
      };

      const { container } = render(
        <TestWrapper>
          <ComponentToRender {...props} />
        </TestWrapper>
      );
      expect(screen.getByText('ACTION 1')).toBeTruthy();
    });
  });

  describe('Carousel', () => {
    it('should render carousel when carouselData is present', () => {
      const props = {
        ...defaultProps,
        content: {
          androidContent: {
            header: 'Header',
            bodyText: 'Body',
            carouselData: [
              {
                title: 'Carousel Item 1',
                message: 'Message 1',
                imageUrl: 'https://image1.url',
              },
              {
                title: 'Carousel Item 2',
                message: 'Message 2',
                imageUrl: 'https://image2.url',
              },
            ],
          },
        },
      };

      render(
        <TestWrapper>
          <ComponentToRender {...props} />
        </TestWrapper>
      );

      expect(screen.getByText('Carousel Item 1')).toBeTruthy();
      expect(screen.getByText('Carousel Item 2')).toBeTruthy();
    });

    it('should render carousel with image media type', () => {
      const props = {
        ...defaultProps,
        content: {
          androidContent: {
            header: 'Header',
            bodyText: 'Body',
            carouselData: [
              {
                mediaType: 'IMAGE',
                imageUrl: 'https://image.url',
                title: 'Title',
                message: 'Message',
              },
            ],
          },
        },
      };

      const { container } = render(
        <TestWrapper>
          <MobilePushPreviewContent {...props} />
        </TestWrapper>
      );

      const image = container.querySelector('.carousel-image');
      expect(image).toBeTruthy();
    });

    it('should render carousel with video media type', () => {
      const props = {
        ...defaultProps,
        content: {
          androidContent: {
            header: 'Header',
            bodyText: 'Body',
            carouselData: [
              {
                mediaType: 'VIDEO',
                videoPreviewImg: 'https://video-preview.url',
                title: 'Title',
                message: 'Message',
              },
            ],
          },
        },
      };

      const { container } = render(
        <TestWrapper>
          <MobilePushPreviewContent {...props} />
        </TestWrapper>
      );

      expect(container.querySelector('.video-preview')).toBeTruthy();
      expect(container.querySelector('.video-icon')).toBeTruthy();
    });

    it('should use url as fallback for imageUrl', () => {
      const props = {
        ...defaultProps,
        content: {
          androidContent: {
            header: 'Header',
            bodyText: 'Body',
            carouselData: [
              {
                mediaType: 'IMAGE',
                url: 'https://url.url',
                title: 'Title',
                message: 'Message',
              },
            ],
          },
        },
      };

      const { container } = render(
        <TestWrapper>
          <MobilePushPreviewContent {...props} />
        </TestWrapper>
      );

      const image = container.querySelector('.carousel-image');
      expect(image.getAttribute('src')).toBe('https://url.url');
    });

    it('should use header as fallback for title', () => {
      const props = {
        ...defaultProps,
        content: {
          androidContent: {
            header: 'Header',
            bodyText: 'Body',
            carouselData: [
              {
                header: 'Carousel Header',
                message: 'Message',
              },
            ],
          },
        },
      };

      render(
        <TestWrapper>
          <ComponentToRender {...props} />
        </TestWrapper>
      );

      expect(screen.getByText('Carousel Header')).toBeTruthy();
    });

    it('should use bodyText as fallback for message', () => {
      const props = {
        ...defaultProps,
        content: {
          androidContent: {
            header: 'Header',
            bodyText: 'Body',
            carouselData: [
              {
                title: 'Title',
                bodyText: 'Carousel Body',
              },
            ],
          },
        },
      };

      render(
        <TestWrapper>
          <ComponentToRender {...props} />
        </TestWrapper>
      );

      expect(screen.getByText('Carousel Body')).toBeTruthy();
    });

    it('should not render carousel when carouselData is empty', () => {
      const props = {
        ...defaultProps,
        content: {
          androidContent: {
            header: 'Header',
            bodyText: 'Body',
            carouselData: [],
          },
        },
      };

      const { container } = render(
        <TestWrapper>
          <MobilePushPreviewContent {...props} />
        </TestWrapper>
      );

      expect(container.querySelector('.mobile-push-carousel-container')).toBeFalsy();
    });
  });

  describe('No Content State', () => {
    it('should render no content message when hasContent is false', () => {
      const props = {
        ...defaultProps,
        content: {
          androidContent: {},
        },
      };

      render(
        <TestWrapper>
          <ComponentToRender {...props} />
        </TestWrapper>
      );

      expect(screen.getByText('No content to preview')).toBeTruthy();
    });
  });

  describe('Device Handling', () => {
    it('should use Android device image for ANDROID device', () => {
      const props = {
        ...defaultProps,
        device: ANDROID,
      };

      const { container } = render(
        <TestWrapper>
          <MobilePushPreviewContent {...props} />
        </TestWrapper>
      );

      expect(container.querySelector('.sms-device-image')).toBeTruthy();
    });

    it('should apply Android class for ANDROID device', () => {
      const props = {
        ...defaultProps,
        device: ANDROID,
      };

      const { container } = render(
        <TestWrapper>
          <MobilePushPreviewContent {...props} />
        </TestWrapper>
      );

      expect(container.querySelector('.android-push-message-Container')).toBeTruthy();
    });

    it('should apply iPhone class for IOS device', () => {
      const props = {
        ...defaultProps,
        device: IOS,
      };

      const { container } = render(
        <TestWrapper>
          <MobilePushPreviewContent {...props} />
        </TestWrapper>
      );

      expect(container.querySelector('.iphone-push-message-Container')).toBeTruthy();
    });
  });

  describe('Edge Cases', () => {
    it('should handle content with only header', () => {
      const props = {
        ...defaultProps,
        content: {
          androidContent: {
            header: 'Header Only',
          },
        },
      };

      render(
        <TestWrapper>
          <ComponentToRender {...props} />
        </TestWrapper>
      );

      expect(screen.getByText('Header Only')).toBeTruthy();
    });

    it('should handle content with only bodyText', () => {
      const props = {
        ...defaultProps,
        content: {
          androidContent: {
            bodyText: 'Body Only',
          },
        },
      };

      render(
        <TestWrapper>
          <ComponentToRender {...props} />
        </TestWrapper>
      );

      expect(screen.getByText('Body Only')).toBeTruthy();
    });

    it('should handle null content', () => {
      const props = {
        ...defaultProps,
        content: null,
      };

      render(
        <TestWrapper>
          <ComponentToRender {...props} />
        </TestWrapper>
      );

      expect(screen.getByText('No content to preview')).toBeTruthy();
    });

    it('should handle empty content object', () => {
      const props = {
        ...defaultProps,
        content: {},
      };

      render(
        <TestWrapper>
          <ComponentToRender {...props} />
        </TestWrapper>
      );

      expect(screen.getByText('No content to preview')).toBeTruthy();
    });
  });

  describe('Default Props', () => {
    it('should use default props when not provided', () => {
      const minimalProps = {
        formatMessage: jest.fn((msg) => msg.defaultMessage || msg.id),
      };

      render(
        <TestWrapper>
          <MobilePushPreviewContent {...minimalProps} />
        </TestWrapper>
      );

      expect(screen.getByText('No content to preview')).toBeTruthy();
    });
  });

  describe('PropTypes Validation', () => {
    it('should accept all required props without warnings', () => {
      const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {});

      render(
        <TestWrapper>
          <MobilePushPreviewContent {...defaultProps} />
        </TestWrapper>
      );

      expect(consoleSpy).not.toHaveBeenCalled();
      consoleSpy.mockRestore();
    });
  });
});
