/**
*
* Beeeditor
*
*/
import React, {
  useEffect, useState, useRef, useCallback,
} from 'react';
import PropTypes from 'prop-types';
import { injectIntl, intlShape, FormattedMessage } from 'react-intl';
import { connect } from 'react-redux';
import { bindActionCreators, compose } from 'redux';
import { createStructuredSelector } from 'reselect';
import { loadItem } from 'services/localStorageApi';
import './index.scss';
import CapModal from "@capillarytech/cap-ui-library/CapModal";
import CapButton from "@capillarytech/cap-ui-library/CapButton";
import CapInput from "@capillarytech/cap-ui-library/CapInput";
import CapSelect from "@capillarytech/cap-ui-library/CapSelect";
import CapSpin from "@capillarytech/cap-ui-library/CapSpin";
import CapNotification from "@capillarytech/cap-ui-library/CapNotification";
import config from '../../config/app';
import makeSelectBEE from './selectors';
import messages from './messages';
import * as beeActions from './actions';
import injectReducer from '../../utils/injectReducer';
import { v2BeeEditionSagas } from './sagas';
import v2BeeEditionReducer from './reducer';

import TagList from '../TagList';
import injectSaga from '../../utils/injectSaga';

import { selectCurrentOrgDetails } from '../Cap/selectors';
function BeeEditor(props) {
  const {
    uid,
    beeJson,
    tokenData,
    id,
    location = {},
    moduleFilterEnabled,
    label,
    className,
    userLocale,
    selectedOfferDetails,
    tags,
    injectedTags,
    saveBeeInstance,
    saveBeeData,
    intl,
    onContextChange,
    actions,
    BEESelect,
    currentOrgDetails,
    eventContextTags,
    waitEventContextTags,
    isGetBeeData,
    getBEEData,
  } = props;
  const { saveRowRequest } = BEESelect;
  const {formatMessage} = intl;
  const UNSUBSCRIBE = 'unsubscribe';
  let beePluginInstance = null;
  const isGetBeeDataRef = useRef(isGetBeeData);
  const categoryOptions = [{key: 'cta', value: 'cta', label: formatMessage(messages.cta)},
    {key: 'footer', value: 'footer', label: formatMessage(messages.footer)},
    {key: 'header', value: 'header', label: formatMessage(messages.header)},
    {key: 'sp', value: 'sp', label: formatMessage(messages.socialPlatform)},
    {key: 'others', value: 'others', label: formatMessage(messages.others)},
  ];
  const [visibleTaglist, setVisibleTaglist] = useState(false);
  const [showRowMetaModal, setRowMetaModal] = useState(false);
  const [selectedTag, setSelectedTag] = useState({});
  const [rowMetaInfo, setRowMetaInfo] = useState({});
  const [rowName, setRowName] = useState('');
  const [rowCategory, setRowCategory] = useState('');
  const beePluginInstanceRef = useRef(null);
  const initializedBeeJsonRef = useRef(null); // Track which beeJson we've initialized for
  const isInitializingRef = useRef(false); // Track if initialization is in progress
  const tokenDataRef = useRef(tokenData); // Store latest tokenData in ref
  let API_ENDPOINT = config.development.api_endpoint;
  if (process.env.NODE_ENV === 'production') {
    API_ENDPOINT = `${window.location.origin}${config.production.api_endpoint}`;
  }
  const savedCallback = useRef();
  const filteredTags = (tags || []).filter((obj) => obj.definition.value !== UNSUBSCRIBE);
  let intervalTimer;

  const DEFAULT_LOCALE = 'en';
  const MAPPED_LOCALE = {
    'en': 'en',
    'zh-cn': 'zh',
    'zh': 'zh',
    'jp': 'jp',
    'ja-JP': 'ja-JP',
  };
  const user = localStorage.getItem('user');
  let locale = 'en';
  if (user && JSON.parse(user).lang) {
    locale = JSON.parse(user).lang;
  }
  const defaultFormattedUrl = locale !== DEFAULT_LOCALE && ['zh-cn', 'zh', 'jp', 'ja-JP'].includes(locale)
    ? `${API_ENDPOINT}/common/getBEECustomLangunage?langid=${MAPPED_LOCALE[locale]}`
    : "";
  useEffect(() => {
    savedCallback.current = Object.keys(selectedTag).length > 0 ? selectedTag : rowMetaInfo;
  }, [selectedTag, rowMetaInfo]);

  const getExternalContentURLs = () => {
    const externalContentURLs = categoryOptions.map((obj) => ({name: obj.label, value: `${API_ENDPOINT}/common/getCustomRows?category=${obj.value}&orgid=${loadItem('orgID')}`}));
    return externalContentURLs;
  };
  // Keep tokenDataRef updated with latest tokenData
  useEffect(() => {
    tokenDataRef.current = tokenData;
  }, [tokenData]);

  useEffect(() => {
    isGetBeeDataRef.current = isGetBeeData;
  }, [isGetBeeData]);

  useEffect(() => {
    // Only initialize if we have both tokenData and beeJson
    const currentTokenData = tokenDataRef.current;
    if (!currentTokenData || !beeJson) {
      return;
    }

    // Normalize beeJson for comparison (handle both string and object)
    // Use a stable key that includes uid to uniquely identify this instance
    let normalizedBeeJson;
    try {
      normalizedBeeJson = typeof beeJson === 'string' ? beeJson : JSON.stringify(beeJson);
    } catch (e) {
      console.warn('[BeeEditor] Error stringifying beeJson:', e);
      normalizedBeeJson = String(beeJson);
    }
    const initializationKey = `${uid}-${normalizedBeeJson}`;

    // Only initialize if:
    // 1. We haven't initialized yet, OR
    // 2. The beeJson has changed (different template)
    // This prevents re-initialization when only tokenData changes
    // Also check if initialization is already in progress to prevent concurrent calls
    if (
      (initializedBeeJsonRef.current === initializationKey && beePluginInstanceRef.current) ||
      isInitializingRef.current
    ) {
      return; // Already initialized for this beeJson or initialization in progress, skip
    }

    // Mark that we're starting initialization
    isInitializingRef.current = true;

    const beeConfig = {
      uid,
      container: 'bee-plugin-container',
      translationsUrl: defaultFormattedUrl,
      rowsConfiguration: {
        emptyRows: true,
        defaultRows: true,
        externalContentURLs: getExternalContentURLs(),
      },
      contentDialog: {
        specialLinks: {
          label: UNSUBSCRIBE,
          handler(resolve) {
            resolve({
              type: 'custom',
              label: UNSUBSCRIBE,
              link: `{{${UNSUBSCRIBE}}}`,
            });
          },
        },
        mergeTags: {
          label: formatMessage(messages.addLabel),
          handler: async (resolve, reject) => {
            // this will open tag modal
            await setVisibleTaglist(true);
            // until tag modal will not open promise will not execute
            // once tag modal is opened it will start 2 sec interval to wait use has selected any tag or cancel the tag selection
            const promise = new Promise((resolveP) => {
              intervalTimer = setInterval(() => {
                // this will execute, if user cancel the tag selection
                if ((savedCallback.current || {}).close === true) {
                  reject();
                  clearInterval(intervalTimer);
                  return;
                }
                // this block is checking use has selected any tag or not
                if (Object.keys(savedCallback.current || {}).length > 0) {
                  resolveP(savedCallback.current);
                  setSelectedTag({});
                  clearInterval(intervalTimer);
                }
              }, 2000);
            });
            // once prmise will resolve , pass the resolve data to handler to show tags in bee edior
            const result = await promise;
            resolve(result);
          },
        },
        saveRow: {
          handler: async (resolve, reject) => {
            await setRowMetaModal(true);
            const promise = new Promise((resolveP) => {
              intervalTimer = setInterval(() => {
                if ((savedCallback.current || {}).close === true) {
                  reject();
                  clearInterval(intervalTimer);
                  setRowMetaInfo({});
                  setRowName('');
                  setRowCategory('');
                  return;
                }
                if (Object.keys(savedCallback.current || {}).length > 0) {
                  resolveP(savedCallback.current);
                }
              }, 2000);
            });
            const result = await promise;
            resolve(result); // "done!"
            setRowMetaInfo({});
            setRowName('');
            setRowCategory('');
            clearInterval(intervalTimer);
          },
        },
      },
      onSave: (jsonFile, htmlFile) => {
        if (isGetBeeDataRef.current && typeof getBEEData === 'function') {
          getBEEData(jsonFile, htmlFile);
          return;
        }
        if (typeof saveBeeData === 'function') {
          saveBeeData(jsonFile, htmlFile);
        }
      },
      onSaveRow: (rowJSON) => {
        actions.createCustomRow(JSON.parse(rowJSON), callbackSaveRow);
      },
    };

    // Clean up previous instance if it exists
    if (beePluginInstanceRef.current) {
      try {
        beePluginInstanceRef.current.destroy();
      } catch (e) {
        console.warn('[BeeEditor] useEffect - Error destroying previous BEE plugin:', e);
      }
      beePluginInstanceRef.current = null;
    }

    try {
      window.BeePlugin.create(currentTokenData, beeConfig, (instance) => {
        beePluginInstance = instance;
        beePluginInstanceRef.current = instance;
        const parseJson = typeof beeJson === 'string' ? JSON.parse(beeJson) : beeJson;
        beePluginInstance.start(parseJson);
        saveBeeInstance(beePluginInstance);
        // Mark this beeJson as initialized and clear initialization flag
        initializedBeeJsonRef.current = initializationKey;
        isInitializingRef.current = false;
      });
    } catch (error) {
      // Reset flag on error
      console.error('[BeeEditor] Error creating BEE plugin:', error);
      isInitializingRef.current = false;
    }
    return () => {
      clearInterval(intervalTimer);
      // Reset initialization flag on cleanup
      isInitializingRef.current = false;
      // Clean up BEE plugin instance if it exists
      if (beePluginInstanceRef.current) {
        try {
          beePluginInstanceRef.current.destroy();
        } catch (e) {
          console.warn('[BeeEditor] useEffect cleanup - Error destroying BEE plugin:', e);
        }
        beePluginInstanceRef.current = null;
      }
      // Note: We don't reset initializedBeeJsonRef here because:
      // 1. If beeJson changes, the effect will run again and the check will allow re-initialization
      // 2. If component unmounts, the ref will be garbage collected anyway
    };
    // Only depend on beeJson, uid, and id - not tokenData
    // tokenData is accessed via ref to prevent re-initialization when it changes
  }, [beeJson, uid, id]);
  const callbackSaveRow = (status, errorMsg) => {
    if (status === 'success') {
      CapNotification.success({message: formatMessage(messages.rowCreationSuccessMgs), key: 'create-custom-row-success'});
    } else {
      CapNotification.error({message: errorMsg || formatMessage(messages.rowCreationFailureMgs), key: 'create-custom-row-failure'});
    }
  };

  const onTagSelect = (result) => {
    const msg = {
      name: result,
      value: `{{${result}}}`,
    };
    setSelectedTag(msg);
    setVisibleTaglist(false);
  };

  const onCancelTagList = () => {
    setVisibleTaglist(false);
    setSelectedTag({close: true});
  };

  const onCustomRowCancel = () => {
    setRowMetaModal(false);
    setRowCategory('');
    setRowName('');
    setRowMetaInfo({close: true});
  };

  const onCustomRowSave = () => {
    const rowInfo = {};
    if (rowCategory !== '') {
      rowInfo.category = rowCategory;
    }
    setRowMetaInfo({
      name: rowName,
      ...rowInfo,
    });
    setRowMetaModal(false);
    setRowCategory('');
    setRowName('');
  };

  const isDisableSave = () => rowName === '' || rowCategory === '';

  const onRowChange = useCallback((e) => {
    setRowName(e.target.value);
  });
  const onChangeCategoy = (e) => {
    setRowCategory(e);
  };
  const contentSection = (
    <>
      <CapInput
        label={<FormattedMessage {...messages.rowName} />}
        placeholder={formatMessage(messages.rowPlaceHolder)}
        onChange={onRowChange}
        value={rowName}
        maxLength={50}
        style={{ width: 324, paddingBottom: 21 }}
      />
      <CapSelect
        label="Category"
        style={{ width: 324, paddingBottom: 24}}
        options={categoryOptions}
        value={rowCategory || undefined}
        placeholder={<FormattedMessage {...messages.selectCategoyPlaceholder} />}
        onChange={onChangeCategoy}
      />

    </>
  );
  return (
    <CapSpin spinning={saveRowRequest || false}>
      <div id="bee-plugin-container" style={{ height: "650px" }}></div>
      <TagList
        moduleFilterEnabled={moduleFilterEnabled}
        label={label}
        onTagSelect={onTagSelect}
        location={location}
        tags={filteredTags}
        injectedTags={injectedTags}
        className={className}
        id={id}
        userLocale={userLocale}
        selectedOfferDetails={selectedOfferDetails}
        visibleTaglist={visibleTaglist}
        hidePopover
        modalProps={{
          onCancel: onCancelTagList,
          style: { left: 135, top: 250 },
          className: "bee-editor-tag-list",
        }}
        onContextChange={onContextChange}
        eventContextTags={eventContextTags}
        waitEventContextTags={waitEventContextTags}
      />
      <CapModal
        className="custom-row-modal"
        visible={showRowMetaModal}
        onCancel={onCustomRowCancel}
        title={formatMessage(messages.customRows)}
        style={{
          width: 372, height: 296, left: 135, top: 300,
        }}
        footer={[
          <CapButton
            key="submit"
            type="primary"
            id="delete-version"
            onClick={onCustomRowSave}
            disabled={isDisableSave()}
          >
            {formatMessage(messages.done)}
          </CapButton>,
        ]}
      >
        {contentSection}
      </CapModal>
    </CapSpin>
  );
}

BeeEditor.propTypes = {
  beeJson: PropTypes.oneOfType([PropTypes.object, PropTypes.string]).isRequired,
  tokenData: PropTypes.oneOfType([PropTypes.object, PropTypes.string]).isRequired,
  uid: PropTypes.string.isRequired,
  intl: intlShape.isRequired,
  actions: PropTypes.object.isRequired,
  BEESelect: PropTypes.object,
  id: PropTypes.string,
  location: PropTypes.object,
  moduleFilterEnabled: PropTypes.bool,
  label: PropTypes.string,
  className: PropTypes.string,
  tags: PropTypes.array,
  saveBeeData: PropTypes.func,
  saveBeeInstance: PropTypes.func,
  injectedTags: PropTypes.object,
  onContextChange: PropTypes.func,
  userLocale: PropTypes.string,
  eventContextTags: PropTypes.array,
  waitEventContextTags: PropTypes.object,
  isGetBeeData: PropTypes.bool,
  getBEEData: PropTypes.func,
};

const mapStateToProps = () => createStructuredSelector({
  BEESelect: makeSelectBEE(),
  currentOrgDetails: selectCurrentOrgDetails(),
});

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators(beeActions, dispatch),
  };
}

const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withSaga = injectSaga({ key: 'beeEditor', saga: v2BeeEditionSagas });
const withReducer = injectReducer({ key: 'beeEditor', reducer: v2BeeEditionReducer });

export default compose(withReducer, withSaga, withConnect)(injectIntl(React.memo(BeeEditor)));
