import React from 'react';

jest.mock('../../CreativesContainer', () => function MockCreativesContainer({
  getCreativesData,
  handleCloseCreatives,
  creativesMode,
  channel,
}) {
  return (
    <div data-testid="creatives-mock" data-creatives-mode={creativesMode} data-creatives-channel={channel}>
      <button
        type="button"
        data-testid="creatives-save"
        onClick={() => getCreativesData({ smsBody: 'Saved' })}
      >
        Save creative
      </button>
      <button type="button" data-testid="creatives-close" onClick={handleCloseCreatives}>
        Close creative
      </button>
    </div>
  );
});

import { Provider } from 'react-redux';
import { configureStore } from '@capillarytech/vulcan-react-sdk/utils';
import {
  render as rtlRender, screen, waitFor, within,
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom';
import { IntlProvider } from 'react-intl';
import history from '../../../utils/history';
import { initialReducer } from '../../../initialReducer';
import CommunicationFlow from '../CommunicationFlow';
import { getEnabledSteps } from '../utils/getEnabledSteps';
import {
  CHANNELS,
  CHANNEL_PRIORITY,
  SINGLE_TEMPLATE,
  STEPS,
} from '../constants';

let store;

beforeAll(() => {
  store = configureStore({}, initialReducer, history);
});

/** Shared option lists for feature config */
const MESSAGE_OPTIONS = [
  { value: 'promotional', label: 'Promotional' },
  { value: 'transactional', label: 'Transactional' },
];

const STRATEGY_OPTIONS = [
  { value: SINGLE_TEMPLATE, label: 'Single template', isMultiChannel: false },
  { value: CHANNEL_PRIORITY, label: 'Channel priority', isMultiChannel: true },
];

const DYNAMIC_CONTROLS = [
  { key: 'sendToControl', label: 'Send to control', description: 'Help text' },
];

/** Base config for all CommunicationFlow tests */
const baseConfig = {
  consumer: 'campaigns',
  mode: 'create',
  features: {},
};

const CAP_DATA = {};

/** Reusable feature presets merged into config.features */
const FEATURES = {
  messageType: {
    messageTypeData: {
      required: true,
      options: MESSAGE_OPTIONS,
      defaultOption: { value: 'promotional', label: 'Promotional' },
    },
  },
  strategyContent: {
    communicationStrategyData: { required: true, options: STRATEGY_OPTIONS, disabled: false },
    contentTemplateData: { required: true, channels: CHANNELS },
  },
  strategyContentDynamic: {
    communicationStrategyData: { required: true, options: STRATEGY_OPTIONS, disabled: false },
    contentTemplateData: { required: true, channels: CHANNELS },
    dynamicControlsData: { required: true, controls: DYNAMIC_CONTROLS },
  },
};

function renderFlow(ui) {
  return rtlRender(
    <Provider store={store}>
      <IntlProvider locale="en" messages={{}} defaultLocale="en">
        {ui}
      </IntlProvider>
    </Provider>,
  );
}

/**
 * Renders connected CommunicationFlow with shared defaults.
 * @param {object} [options]
 * @param {object} [options.features] — config.features (use FEATURES.* or custom)
 * @param {object|null} [options.initialData]
 * @param {object} [options.capData]
 * @param {jest.Mock} [options.onSave] — defaults to jest.fn()
 * @param {jest.Mock} [options.onCancel] — defaults to jest.fn()
 * @param {jest.Mock} [options.onChange]
 */
function renderWithFlow({
  features = {},
  initialData = null,
  capData = CAP_DATA,
  onSave,
  onCancel,
  onChange,
  ...rest
} = {}) {
  return renderFlow(
    <CommunicationFlow
      config={{ ...baseConfig, features }}
      initialData={initialData}
      onSave={onSave ?? jest.fn()}
      onCancel={onCancel ?? jest.fn()}
      onChange={onChange}
      capData={capData}
      {...rest}
    />,
  );
}

async function selectCommunicationStrategy(label) {
  const combo = screen.getByRole('combobox');
  await userEvent.click(combo);
  await waitFor(() => {
    expect(screen.getByRole('listbox')).toBeInTheDocument();
  });
  await userEvent.click(within(screen.getByRole('listbox')).getByText(label));
}

describe('getEnabledSteps', () => {
  it('includes delivery settings when deliverySettingsData.required is true', () => {
    const steps = getEnabledSteps({
      ...baseConfig,
      features: {
        deliverySettingsData: { required: true },
      },
    });
    expect(steps).toContain(STEPS.DELIVERY_SETTINGS);
  });

  it('omits delivery settings when deliverySettingsData.required is absent or false', () => {
    expect(getEnabledSteps({ ...baseConfig, features: {} })).not.toContain(
      STEPS.DELIVERY_SETTINGS,
    );
    expect(
      getEnabledSteps({
        ...baseConfig,
        features: { deliverySettingsData: { required: false } },
      }),
    ).not.toContain(STEPS.DELIVERY_SETTINGS);
  });
});

describe('CommunicationFlow', () => {
  it('renders only steps whose features are required', () => {
    renderWithFlow({ features: FEATURES.messageType });
    expect(screen.getByText(/message type/i)).toBeInTheDocument();
    expect(screen.queryByText(/communication strategy/i)).not.toBeInTheDocument();
    expect(screen.queryByText(/content template/i)).not.toBeInTheDocument();
  });

  it('hides channel selection and dynamic controls until a communication strategy is set', async () => {
    renderWithFlow({ features: FEATURES.strategyContentDynamic });

    expect(screen.queryByText(/content template/i)).not.toBeInTheDocument();
    expect(screen.queryByText(/other controls/i)).not.toBeInTheDocument();

    await selectCommunicationStrategy('Single template');

    await waitFor(() => {
      expect(screen.getAllByText(/content template/i).length).toBeGreaterThan(0);
    });
    expect(screen.getByText(/other controls/i)).toBeInTheDocument();
  });

  it('calls onChange with aggregated data when step data updates', async () => {
    const onChange = jest.fn();
    renderWithFlow({ features: FEATURES.messageType, onChange });

    onChange.mockClear();
    await userEvent.click(screen.getByRole('radio', { name: /transactional/i }));

    expect(onChange).toHaveBeenCalled();
    const payload = onChange.mock.calls[onChange.mock.calls.length - 1][0];
    expect(payload.messageType).toBe('transactional');
    expect(payload.communicationStrategy).toBeNull();
  });

  it('passes single-channel aggregate to onSave', async () => {
    const onSave = jest.fn();
    renderWithFlow({ features: FEATURES.strategyContent, onSave });

    await selectCommunicationStrategy('Single template');

    await userEvent.click(screen.getByRole('button', { name: /content template/i }));
    await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument());
    await userEvent.click(within(screen.getByRole('menu')).getByText('SMS'));

    await waitFor(() => expect(screen.getByTestId('creatives-mock')).toBeInTheDocument());
    await userEvent.click(screen.getByRole('button', { name: /save creative/i }));

    await waitFor(() => expect(screen.queryByTestId('creatives-mock')).not.toBeInTheDocument());

    await userEvent.click(screen.getByRole('button', { name: /^save$/i }));

    expect(onSave).toHaveBeenCalledTimes(1);
    const saved = onSave.mock.calls[0][0];
    expect(saved.communicationStrategy).toBe(SINGLE_TEMPLATE);
    expect(saved.channel).toBe('SMS');
    expect(saved.channels).toEqual([]);
    expect(saved.contentItems.length).toBeGreaterThanOrEqual(1);
  });

  it('clears channel and keeps channels list in aggregate for multi-channel strategy', async () => {
    const onSave = jest.fn();
    renderWithFlow({
      features: FEATURES.strategyContent,
      initialData: {
        communicationStrategy: CHANNEL_PRIORITY,
        channels: ['SMS', 'EMAIL'],
      },
      onSave,
    });

    await userEvent.click(screen.getByRole('button', { name: /^save$/i }));

    const saved = onSave.mock.calls[0][0];
    expect(saved.communicationStrategy).toBe(CHANNEL_PRIORITY);
    expect(saved.channel).toBeNull();
    expect(saved.channels).toEqual(['SMS', 'EMAIL']);
  });

  it('initializes message type from initialData when provided', () => {
    renderWithFlow({
      features: FEATURES.messageType,
      initialData: { messageType: 'transactional' },
    });
    expect(screen.getByRole('radio', { name: /transactional/i })).toBeChecked();
  });
});
