import React from 'react';
import "@testing-library/jest-dom";
import { configureStore }  from '@capillarytech/vulcan-react-sdk/utils';
import { initialReducer } from '../../../initialReducer';
import { injectIntl } from "react-intl";
import { fireEvent } from "@testing-library/react";
import { TagList } from '../index';
import { TagListData, eventContextTags, waitEventContextTags } from './mockdata';
import { OfferTag, badgesTags, offer } from '../../../utils/tests/common.mockdata';
import * as commonUtils from "../../../utils/common";
import { Provider } from 'react-redux';
import { screen, render } from '../../../utils/test-utils';
import history from '../../../utils/history';
const { getByText, queryByText } = screen;

const buildProps = (props = {}) => ({
  ...TagListData,
  onTagSelect: jest.fn(),
  ...props,
});

const initializeTagList = (props = {}) => {
  const store = configureStore({}, initialReducer, history);
  const Component = injectIntl(TagList);
  const propsObj = buildProps(props);
  return {
    ...render(
      <Provider store={store}>
        <Component {...propsObj} />
      </Provider>
    ),
    store,
    Component,
    propsObj,
  };
};

const addLabelBtnAssertion = () => {
  const addLabelButton = screen.getByText(/add label/i);
  expect(addLabelButton).toBeInTheDocument();
  fireEvent.click(addLabelButton);
};

describe("TagList test :  UNIT", () => {
  it("should render the TagList component with default props amd addLabel Button", async () => {
    initializeTagList();
    addLabelBtnAssertion();
  });

  it('should render event context tag section from generateTags', () => {
    initializeTagList({ eventContextTags, moduleFilterEnabled: false });
    addLabelBtnAssertion();
    const EVENT_CONTEXT_TAG_HEADER = getByText(/Entry event/i);
    expect(EVENT_CONTEXT_TAG_HEADER).toBeInTheDocument();

    // Behavioural event profile tags should not be visible as label and profile name is not present
    const BEHAVIOURAL_EVENT_PROFILE = queryByText(/Behavioural event/i);
    expect(BEHAVIOURAL_EVENT_PROFILE).not.toBeInTheDocument();
  });

  it('should render wait event context section when waitEventContextTags is provided', () => {
    initializeTagList({ waitEventContextTags, moduleFilterEnabled: false });
    addLabelBtnAssertion();
    const WAIT_EVENT_HEADER = getByText(/Order Placed \(Wait Block\)/i);
    expect(WAIT_EVENT_HEADER).toBeInTheDocument();
  });

  it('should merge empty waitEventContextTags with entry event tags', () => {
    initializeTagList({ eventContextTags, waitEventContextTags: {}, moduleFilterEnabled: false });
    addLabelBtnAssertion();
    expect(getByText(/Entry event/i)).toBeInTheDocument();
  });

  it('calls parent onContextChange with Outbound when tags and injectedTags are empty on popover open', () => {
    const onContextChange = jest.fn();
    initializeTagList({
      tags: [],
      injectedTags: {},
      onContextChange,
      onTagSelect: jest.fn(),
    });
    // Default fetch is triggered when the Add Label popover opens (not on mount)
    addLabelBtnAssertion();
    expect(onContextChange).toHaveBeenCalledWith('Outbound');
  });

  it('applies fetchingSchemaError from props via componentWillReceiveProps', () => {
    const { rerender, Component, propsObj, store } = initializeTagList({ fetchingSchemaError: false });
    addLabelBtnAssertion();
    rerender(
      <Provider store={store}>
        <Component {...propsObj} fetchingSchemaError />
      </Provider>
    );
    expect(screen.getByText(/add label/i)).toBeInTheDocument();
  });

  it('disables Add label when restrictPersonalization is true', () => {
    initializeTagList({
      restrictPersonalization: true,
      disabled: false,
      moduleFilterEnabled: false,
    });
    const btn = screen.getByText(/add label/i).closest('button');
    expect(btn).toBeDisabled();
  });

  it('calls transformCouponTags when selectedOfferDetails and coupon tags are present', () => {
    const spy = jest.spyOn(TagList.prototype, 'transformCouponTags');
    initializeTagList({
      tags: OfferTag,
      injectedTags: {},
      selectedOfferDetails: [{ id: 'c1', couponName: 'Promo Coupon', couponSeriesId: 'c1' }],
      moduleFilterEnabled: false,
    });
    expect(spy).toHaveBeenCalled();
    spy.mockRestore();
  });

  it('calls transformBadgeTags from common when badge offer and Badge tags are present', () => {
    const spy = jest.spyOn(commonUtils, 'transformBadgeTags');
    initializeTagList({
      tags: badgesTags,
      injectedTags: {},
      selectedOfferDetails: offer,
      moduleFilterEnabled: false,
    });
    expect(spy).toHaveBeenCalled();
    spy.mockRestore();
  });

  it('unmounts without throwing', () => {
    const { unmount } = initializeTagList();
    expect(() => unmount()).not.toThrow();
  });

  it('regenerates tags when props.tags change (componentDidUpdate)', () => {
    const { rerender, Component, store } = initializeTagList({ tags: TagListData.tags });
    const extra = [
      ...TagListData.tags,
      {
        _id: 'extra-tag',
        type: 'TAG',
        definition: {
          label: { en: 'Extra' },
          value: 'extra_value',
          subtags: [],
          'tag-header': false,
          supportedModules: [{ context: 'default', layout: 'sms', mandatory: false }],
        },
        scope: { tag: 'STANDARD', orgId: -1, verticals: [] },
        isActive: true,
      },
    ];
    rerender(
      <Provider store={store}>
        <Component {...buildProps({ tags: extra })} />
      </Provider>
    );
    addLabelBtnAssertion();
    expect(screen.getByText(/add label/i)).toBeInTheDocument();
  });
});
