import React from 'react';
import { render, screen, fireEvent, act } from '@testing-library/react';
import '@testing-library/jest-dom';
import { Provider } from 'react-redux';
import { IntlProvider } from 'react-intl';
import { configureStore } from '@capillarytech/vulcan-react-sdk/utils';
import { initialReducer } from '../../../../initialReducer';
import history from '../../../../utils/history';
import CtaButtons from '../CtaButtons';
import { PRIMARY, SECONDARY, DEEP_LINK } from '../../constants';

// Mock the UI components
jest.mock('@capillarytech/cap-ui-library/CapRow', () => 
  function MockCapRow({ children }) {
    return <div data-testid="cap-row">{children}</div>;
  }
);

jest.mock('@capillarytech/cap-ui-library/CapButton', () => 
  function MockCapButton({ children, onClick, id, type, ...props }) {
    return (
      <button
        data-testid={id || 'cap-button'}
        onClick={onClick}
        type={type || 'button'}
        {...props}
      >
        {children}
      </button>
    );
  }
);

jest.mock('@capillarytech/cap-ui-library/CapIcon', () => 
  function MockCapIcon({ type }) {
    return <span data-testid="cap-icon" data-icon-type={type} />;
  }
);

jest.mock('@capillarytech/cap-ui-library/CapHeading', () => 
  function MockCapHeading({ children, type, id }) {
    return (
      <div data-testid={id || 'cap-heading'} data-heading-type={type}>
        {children}
      </div>
    );
  }
);

// Mock the CapMpushCTA component
jest.mock('../../../../v2Components/CapMpushCTA', () => 
  function MockCapMpushCTA({ ctaData, updateHandler, deleteHandler, buttonType }) {
    return (
      <div data-testid="cap-mpush-cta" data-button-type={buttonType}>
        <button
          data-testid={`${buttonType}-cta-update`}
          onClick={() => updateHandler({ text: 'Updated' }, buttonType === 'PRIMARY' ? 0 : 1)}
        >
          Update CTA
        </button>
        <button
          data-testid={`${buttonType}-cta-delete`}
          onClick={() => deleteHandler(buttonType === 'PRIMARY' ? 0 : 1)}
        >
          Delete CTA
        </button>
      </div>
    );
  }
);

// Mock the constants
jest.mock('../../constants', () => ({
  PRIMARY: 'PRIMARY',
  SECONDARY: 'SECONDARY',
  DEEP_LINK: 'DEEP_LINK',
}));

// Mock the messages
jest.mock('../../messages', () => ({
  buttons: {
    id: 'buttons',
    defaultMessage: 'Buttons',
  },
  addPrimaryButton: {
    id: 'add.primary.button',
    defaultMessage: 'Add primary button',
  },
  addSecondaryButton: {
    id: 'add.secondary.button',
    defaultMessage: 'Add secondary button',
  },
  secondaryButtonTooltip: {
    id: 'secondary.button.tooltip',
    defaultMessage: 'Secondary button tooltip',
  },
}));

const mockStore = configureStore({}, initialReducer, history);

const defaultProps = {
  primaryButton: false,
  secondaryButton: false,
  setPrimaryButton: jest.fn(),
  setSecondaryButton: jest.fn(),
  ctaData: [],
  updateHandler: jest.fn(),
  deleteHandler: jest.fn(),
  deepLink: [],
};

const renderComponent = (props = {}) => {
  const mergedProps = { ...defaultProps, ...props };
  return render(
    <Provider store={mockStore}>
      <IntlProvider locale="en" messages={{}}>
        <CtaButtons {...mergedProps} />
      </IntlProvider>
    </Provider>
  );
};

describe('CtaButtons', () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  describe('Initial Rendering', () => {
    it('should render the component with default props', () => {
      renderComponent();
      expect(screen.getByTestId('cap-row')).toBeInTheDocument();
      expect(screen.getByText('Buttons')).toBeInTheDocument();
    });

    it('should render add primary button when no primary button exists', () => {
      renderComponent();
      expect(screen.getByTestId('add-primary-button')).toBeInTheDocument();
      expect(screen.getByText('Add primary button')).toBeInTheDocument();
    });

    it('should not render add primary button when primary button is saved', () => {
      const ctaData = [
        { index: 0, text: 'Primary Button', isSaved: true }
      ];
      renderComponent({ ctaData });
      expect(screen.queryByTestId('add-primary-button')).not.toBeInTheDocument();
    });

    it('should not render add primary button when primary CTA is being shown', () => {
      const ctaData = [
        { index: 0, text: 'Primary Button', ctaType: 'PRIMARY' }
      ];
      renderComponent({ primaryButton: true, ctaData });
      expect(screen.queryByTestId('add-primary-button')).not.toBeInTheDocument();
    });
  });

  describe('Primary Button Functionality', () => {
    it('should handle adding primary button', () => {
      const setPrimaryButton = jest.fn();
      const updateHandler = jest.fn();
      
      renderComponent({ setPrimaryButton, updateHandler });
      
      fireEvent.click(screen.getByTestId('add-primary-button'));
      
      expect(updateHandler).toHaveBeenCalledWith({
        index: 0,
        ctaType: 'PRIMARY',
        text: "",
        urlType: 'DEEP_LINK',
        url: "",
        deepLinkKeys: "",
        isSaved: false,
      }, 0);
      expect(setPrimaryButton).toHaveBeenCalledWith(true);
    });

    it('should prevent multiple clicks when primary button is already being added', () => {
      const setPrimaryButton = jest.fn();
      const updateHandler = jest.fn();
      const ctaData = [
        { index: 0, text: 'Primary Button', ctaType: 'PRIMARY' }
      ];
      
      renderComponent({ 
        primaryButton: true, 
        ctaData,
        setPrimaryButton, 
        updateHandler 
      });
      
      // Should not render add button when primaryButton is true and button exists
      expect(screen.queryByTestId('add-primary-button')).not.toBeInTheDocument();
    });

    it('should not initialize primary button if it already exists in ctaData', () => {
      const updateHandler = jest.fn();
      const ctaData = [
        { index: 0, text: 'Existing Primary', ctaType: 'PRIMARY' }
      ];
      
      renderComponent({ primaryButton: true, ctaData, updateHandler });
      
      // Since primary button exists and primaryButton is true, add button should not be shown
      expect(screen.queryByTestId('add-primary-button')).not.toBeInTheDocument();
    });

    it('should show primary CTA when primary button is active and exists', () => {
      const ctaData = [
        { index: 0, text: 'Primary Button', ctaType: 'PRIMARY' }
      ];
      
      renderComponent({ 
        primaryButton: true, 
        ctaData 
      });
      
      expect(screen.getByTestId('cap-mpush-cta')).toBeInTheDocument();
      expect(screen.getByTestId('cap-mpush-cta')).toHaveAttribute('data-button-type', 'PRIMARY');
    });
  });

  describe('Secondary Button Functionality', () => {
    it('should render add secondary button when primary button is saved', () => {
      const ctaData = [
        { index: 0, text: 'Primary Button', isSaved: true }
      ];
      
      renderComponent({ ctaData });
      
      expect(screen.getByTestId('add-secondary-button')).toBeInTheDocument();
      expect(screen.getByText('Add secondary button')).toBeInTheDocument();
    });

    it('should not render add secondary button when primary button is not saved', () => {
      const ctaData = [
        { index: 0, text: 'Primary Button', isSaved: false }
      ];
      
      renderComponent({ ctaData });
      
      expect(screen.queryByTestId('add-secondary-button')).not.toBeInTheDocument();
    });

    it('should handle adding secondary button', () => {
      const setSecondaryButton = jest.fn();
      const updateHandler = jest.fn();
      const ctaData = [
        { index: 0, text: 'Primary Button', isSaved: true }
      ];
      
      renderComponent({ 
        ctaData, 
        setSecondaryButton, 
        updateHandler 
      });
      
      // The secondary button should be disabled when primary button is saved
      const secondaryButton = screen.getByTestId('add-secondary-button');
      expect(secondaryButton).toBeDisabled();
      
      // Since the button is disabled, clicking it should not trigger the handlers
      fireEvent.click(secondaryButton);
      
      // The handlers should not be called because the button is disabled
      expect(updateHandler).not.toHaveBeenCalled();
      expect(setSecondaryButton).not.toHaveBeenCalled();
    });

    it('should handle adding secondary button when primary button is not saved', () => {
      const setSecondaryButton = jest.fn();
      const updateHandler = jest.fn();
      const ctaData = [
        { index: 0, text: 'Primary Button', isSaved: false }
      ];
      
      renderComponent({ 
        ctaData, 
        setSecondaryButton, 
        updateHandler 
      });
      
      // The secondary button should not be rendered when primary button is not saved
      expect(screen.queryByTestId('add-secondary-button')).not.toBeInTheDocument();
    });

    it('should prevent multiple clicks when secondary button is already being added', () => {
      const setSecondaryButton = jest.fn();
      const updateHandler = jest.fn();
      const ctaData = [
        { index: 0, text: 'Primary Button', isSaved: true },
        { index: 1, text: 'Secondary Button', ctaType: 'SECONDARY' }
      ];
      
      renderComponent({ 
        ctaData,
        secondaryButton: true,
        setSecondaryButton, 
        updateHandler 
      });
      
      // Should not render add button when secondaryButton is true and button exists
      expect(screen.queryByTestId('add-secondary-button')).not.toBeInTheDocument();
    });

    it('should not render add secondary button when secondary button is saved', () => {
      const ctaData = [
        { index: 0, text: 'Primary Button', isSaved: true },
        { index: 1, text: 'Secondary Button', isSaved: true }
      ];
      
      renderComponent({ ctaData });
      
      expect(screen.queryByTestId('add-secondary-button')).not.toBeInTheDocument();
    });

    it('should show secondary CTA when secondary button is active and exists', () => {
      const ctaData = [
        { index: 0, text: 'Primary Button', isSaved: true },
        { index: 1, text: 'Secondary Button', ctaType: 'SECONDARY' }
      ];
      
      renderComponent({ 
        secondaryButton: true, 
        ctaData 
      });
      
      const secondaryCTA = screen.getByTestId('cap-mpush-cta');
      expect(secondaryCTA).toBeInTheDocument();
      expect(secondaryCTA).toHaveAttribute('data-button-type', 'SECONDARY');
    });
  });

  describe('Delete Handler', () => {
    it('should handle deleting primary button', () => {
      const setPrimaryButton = jest.fn();
      const deleteHandler = jest.fn();
      const ctaData = [
        { index: 0, text: 'Primary Button', ctaType: 'PRIMARY' }
      ];
      
      renderComponent({ 
        primaryButton: true,
        ctaData,
        setPrimaryButton,
        deleteHandler
      });
      
      fireEvent.click(screen.getByTestId(`PRIMARY-cta-delete`));
      
      expect(setPrimaryButton).toHaveBeenCalledWith(false);
      expect(deleteHandler).toHaveBeenCalledWith(0);
    });
    //not required as of now as secondary button is not supported from BE & Hydra
    // it('should handle deleting secondary button', () => {
    //   const setSecondaryButton = jest.fn();
    //   const deleteHandler = jest.fn();
    //   const ctaData = [
    //     { index: 0, text: 'Primary Button', isSaved: true },
    //     { index: 1, text: 'Secondary Button', ctaType: 'SECONDARY' }
    //   ];
      
    //   renderComponent({ 
    //     secondaryButton: true,
    //     ctaData,
    //     setSecondaryButton,
    //     deleteHandler
    //   });
      
    //   fireEvent.click(screen.getByTestId(`SECONDARY-cta-delete`));
      
    //   expect(setSecondaryButton).toHaveBeenCalledWith(false);
    //   expect(deleteHandler).toHaveBeenCalledWith(1);
    // });
  });

  describe('Component Structure', () => {
    it('should render proper component structure', () => {
      renderComponent();
      
      expect(screen.getByTestId('cap-row')).toBeInTheDocument();
      expect(screen.getByTestId('cap-heading')).toBeInTheDocument();
      expect(screen.getByTestId('cap-icon')).toBeInTheDocument();
      expect(screen.getByTestId('cap-icon')).toHaveAttribute('data-icon-type', 'plus');
    });

    it('should render heading with correct type', () => {
      renderComponent();
      
      expect(screen.getByTestId('cap-heading')).toHaveAttribute('data-heading-type', 'h3');
    });

    it('should render button headings with correct type', () => {
      renderComponent();
      
      expect(screen.getByTestId('add-primary-btn-heading')).toHaveAttribute('data-heading-type', 'h5');
    });
  });

  describe('Edge Cases', () => {
    it('should handle early return when primary button exists and showPrimaryCTA is true', () => {
      const updateHandler = jest.fn();
      const setPrimaryButton = jest.fn();
      const ctaData = [
        { index: 0, text: 'Primary Button', ctaType: 'PRIMARY' }
      ];
      
      renderComponent({ 
        primaryButton: true,
        ctaData,
        updateHandler,
        setPrimaryButton
      });
      
      // Since primaryButton is true and button exists, updateHandler should not be called
      expect(updateHandler).not.toHaveBeenCalled();
    });

    it('should handle early return when secondary button exists and showSecondaryCTA is true', () => {
      const updateHandler = jest.fn();
      const setSecondaryButton = jest.fn();
      const ctaData = [
        { index: 0, text: 'Primary Button', isSaved: true },
        { index: 1, text: 'Secondary Button', ctaType: 'SECONDARY' }
      ];
      
      renderComponent({ 
        secondaryButton: true,
        ctaData,
        updateHandler,
        setSecondaryButton
      });
      
      // Since secondaryButton is true and button exists, updateHandler should not be called
      expect(updateHandler).not.toHaveBeenCalled();
    });

    it('should handle early return when shouldShowSecondaryCTA is true', () => {
      const updateHandler = jest.fn();
      const setSecondaryButton = jest.fn();
      const ctaData = [
        { index: 0, text: 'Primary Button', isSaved: true },
        { index: 1, text: 'Secondary Button', ctaType: 'SECONDARY' }
      ];
      
      renderComponent({ 
        secondaryButton: true,
        ctaData,
        updateHandler,
        setSecondaryButton
      });
      
      // Since shouldShowSecondaryCTA is true, updateHandler should not be called
      expect(updateHandler).not.toHaveBeenCalled();
    });

    it('should handle early return in handleAddPrimary when primaryButton and showPrimaryCTA are true', () => {
      const updateHandler = jest.fn();
      const setPrimaryButton = jest.fn();
      
      const { rerender } = renderComponent({ 
        primaryButton: true,
        updateHandler,
        setPrimaryButton
      });

      // First click to set showPrimaryCTA to true
      const addButton = screen.getByTestId('add-primary-button');
      fireEvent.click(addButton);

      // Clear the mock calls
      updateHandler.mockClear();
      setPrimaryButton.mockClear();

      // Re-render with primaryButton true and showPrimaryCTA true (from previous click)
      rerender(
        <Provider store={mockStore}>
          <IntlProvider locale="en" messages={{}}>
            <CtaButtons 
              {...defaultProps}
              primaryButton={true}
              updateHandler={updateHandler}
              setPrimaryButton={setPrimaryButton}
            />
          </IntlProvider>
        </Provider>
      );

      // Try to click again - should hit early return
      if (screen.queryByTestId('add-primary-button')) {
        fireEvent.click(screen.getByTestId('add-primary-button'));
        expect(updateHandler).not.toHaveBeenCalled();
        expect(setPrimaryButton).not.toHaveBeenCalled();
      }
    });

    it('should handle early return in handleAddSecondary when secondaryButton and showSecondaryCTA are true', () => {
      const updateHandler = jest.fn();
      const setSecondaryButton = jest.fn();
      const ctaData = [
        { index: 0, text: 'Primary Button', isSaved: true }
      ];
      
      const { rerender } = renderComponent({ 
        secondaryButton: true,
        ctaData,
        updateHandler,
        setSecondaryButton
      });

      // First click to set showSecondaryCTA to true
      const addButton = screen.getByTestId('add-secondary-button');
      fireEvent.click(addButton);

      // Clear the mock calls
      updateHandler.mockClear();
      setSecondaryButton.mockClear();

      // Re-render with secondaryButton true and showSecondaryCTA true (from previous click)
      rerender(
        <Provider store={mockStore}>
          <IntlProvider locale="en" messages={{}}>
            <CtaButtons 
              {...defaultProps}
              secondaryButton={true}
              ctaData={ctaData}
              updateHandler={updateHandler}
              setSecondaryButton={setSecondaryButton}
            />
          </IntlProvider>
        </Provider>
      );

      // Try to click again - should hit early return
      if (screen.queryByTestId('add-secondary-button')) {
        fireEvent.click(screen.getByTestId('add-secondary-button'));
        expect(updateHandler).not.toHaveBeenCalled();
        expect(setSecondaryButton).not.toHaveBeenCalled();
      }
    });

    it('should handle early return in handleAddSecondary when shouldShowSecondaryCTA is true', () => {
      const updateHandler = jest.fn();
      const setSecondaryButton = jest.fn();
      const ctaData = [
        { index: 0, text: 'Primary Button', isSaved: true },
        { index: 1, text: 'Secondary Button', ctaType: 'SECONDARY' }
      ];
      
      renderComponent({ 
        secondaryButton: true,
        ctaData,
        updateHandler,
        setSecondaryButton
      });

      // Since shouldShowSecondaryCTA is true (secondaryButton is true and button exists),
      // the add button should not be rendered
      expect(screen.queryByTestId('add-secondary-button')).not.toBeInTheDocument();
      expect(updateHandler).not.toHaveBeenCalled();
      expect(setSecondaryButton).not.toHaveBeenCalled();
    });
  });
});