/**
*
* CapTagList
*
*/

import PropTypes from 'prop-types';
import React from 'react';
import { connect } from 'react-redux';
import moment from 'moment';
import { FONT_COLOR_05 } from '@capillarytech/cap-ui-library/styled/variables';
// import styled from 'styled-components';
import {
  CapSpin,
  CapModal,
  CapButton,
  CapPopover,
  CapInput,
  CapTree,
  CapSelect,
  CapTooltip,
  CapLink,
  CapIcon,
  CapRow,
  CapLabel,
} from "@capillarytech/cap-ui-library";
import './style.scss';
import _ from 'lodash';
import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
import { createStructuredSelector } from 'reselect';
import messages from './messages';
import { makeSelectLoyaltyPromotionDisplay } from '../../v2Containers/Cap/selectors';
import { CARD_RELATED_TAGS, HOSPITALITY_RELATED_TAGS, CUSTOMER_BARCODE_TAG, GET_TRANSLATION_MAPPED ,JAPANESE_HELP_TEXT, TAG_TRANSLATION_DOC} from '../../constants/unified';
import { hasCardBasedScope, hasCustomerBarcodeFeatureEnabled, hasHospitalityBasedScope } from '../../utils/common';
import { EMAIL, JP_LOCALE_HIDE_FEATURE, LOYALTY } from '../../v2Containers/App/constants';
import { hidingDateTagsForJpLocale } from '../../v2Containers/TagList/utils';


const {Search} = CapInput;

class CapTagList extends React.Component { // eslint-disable-line react/prefer-stateless-function
  constructor(props) {
    super(props);
    this.state = {
      tagValue: '',
      selectedNodeKey: '',
      expandedKeys: [],
      searchValue: '',
      autoExpandParent: true,
      visible: false,
      dynamicDateValue: '',
      showModal: false,
      translationLang: '',
      tagsList: [],
      selectedContext: 'Outbound',
      isLoadingLoyaltyTags: false,
      isLoadingContextChange: false,
    };
    this.renderTags = this.renderTags.bind(this);
    this.getSearchedExpandedKeys = this.getSearchedExpandedKeys.bind(this);
  }

  getTranslationMappedLocale(locale) {
    return GET_TRANSLATION_MAPPED?.[locale];
  }

  componentDidMount() {
    const user = localStorage.getItem('user');
    let locale = 'en';
    moment.locale(locale);
    if (user) {
      locale = JSON.parse(user).lang || locale;
    }
    locale = this.getTranslationMappedLocale(locale);
    this.setState({
      translationLang: locale,
    });
  }

  componentDidUpdate(prevProps, prevState) {
    if (this.props.tags !== prevProps.tags || this.state.searchValue !== prevState.searchValue) {
      const temp = this.renderTags(this.props.tags);
      this.setState({
        tagsList: temp,
      });
    }

    // Reset loading states when tags are received after context change
    if ((this.state.isLoadingLoyaltyTags || this.state.isLoadingContextChange)
        && this.props.tags !== prevProps.tags) {
      this.setState({
        isLoadingLoyaltyTags: false,
        isLoadingContextChange: false,
      });
    }

    // Backup: Reset loading states if props.loading changed from true to false
    // This handles cases where the API doesn't return different tags but injectedTags change
    if (prevProps.loading === true && this.props.loading === false
        && (this.state.isLoadingLoyaltyTags || this.state.isLoadingContextChange)) {
      this.setState({ 
        isLoadingLoyaltyTags: false,
        isLoadingContextChange: false,
      });
    }
  }

  onChange = (e) => {
    const {value} = e.target;
    let expandedKeys = this.getSearchedExpandedKeys(this.props.tags, value);
    if (value === '') {
      expandedKeys = [];
    }
    this.setState({
      expandedKeys,
      searchValue: value,
      autoExpandParent: true,
    });
  };

  onExpand = (expandedKeys, info) => {
    const node = info?.node;
    const eventKey = node?.eventKey ?? node?.key ?? node?.props?.eventKey;
    this.handleOnExpand(eventKey);
  };

  getSearchedExpandedKeys(tags, value = '', parentPath = '') {
    let list = [];
    _.forEach(tags, (val = {}, key) => {
      const rawKey = val?.incentiveSeriesId ? `${key}(${val?.incentiveSeriesId})` : `${key}`;
      const nodeKey = parentPath ? `${parentPath}.${rawKey}` : rawKey;
      const tagName =
        typeof val?.name === 'string'
          ? _.toLower(_.get(val, "name", ""))
          : _.toLower(_.get(val, "name.props.defaultMessage", ""));
      const tagNameWithoutUnderscore = tagName.replace(/_/g, " ");
      const searchStringLower = _.toLower(value);
      if (_.has(val, "subtags")) {
        const temp = this.getSearchedExpandedKeys(val?.subtags, value, nodeKey);
        const nodeMatches = val?.name
          && (tagName.includes(searchStringLower)
            || tagNameWithoutUnderscore.includes(searchStringLower));
        if (nodeMatches || temp.length > 0) {
          list.push(nodeKey);
        }
        list = list.concat(temp);
      } else if (
        val?.name
        && (tagName.includes(searchStringLower)
          || tagNameWithoutUnderscore.includes(searchStringLower))
      ) {
        list.push(nodeKey);
      }
    });
    return list;
  }

  handleOnChange = (data) => {
    const { selectedContext } = this.state;

    // Only proceed if the context has actually changed
    if (selectedContext !== data) {
      // Set loading state for any context change
      this.setState({
        isLoadingContextChange: true,
        selectedContext: data,
        // Keep loyalty-specific loading for backward compatibility
        isLoadingLoyaltyTags: data === LOYALTY,
      });

      // Call the parent's context change handler
      this.props.onContextChange(data);
    }
  };

  handleDynamicDateChange = (data) => {
    this.setState({dynamicDateValue: data.target.value});
  };

  handleOk = () => {
    const days = this.state.dynamicDateValue;
    let tagValue = this.state.tagValue;
    tagValue = tagValue.replace("(N)", `${days}`);
    const resultArray = [];
    resultArray.push(tagValue);
    this.setState({showModal: false, dynamicDateValue: ''});
    this.props.onSelect(resultArray);
  };

  handleCancel = () => {
    this.setState({showModal: false, dynamicDateValue: ''});
  };

  checkIfDynamicTag = (tag) => {
    const regex = /dynamic_expiry_date_after_\(N\)_days.FORMAT_\d/g;
    const match = regex.exec(tag);
    if (match !== null) {
      return true;
    }
    return false;
  };

  handleOnSelect = (selectedKeys, info) => {
    if (selectedKeys.length > 0) {
      const selectedNode = info?.selectedNodes?.[0];
      if (!selectedNode) {
        return;
      }
      const isLeaf = selectedNode.isLeaf ?? selectedNode.props?.isLeaf;
      if (isLeaf) {
        const tagKey = selectedNode.tagKey ?? selectedNode.props?.tagKey;
        const selectedTagValue = tagKey || selectedKeys[0];
        this.setState({
          tagValue: selectedTagValue,
          selectedNodeKey: selectedKeys[0],
        });
        const ifDynamicTag = this.checkIfDynamicTag(selectedTagValue);
        if (ifDynamicTag) {
          this.renderDynamicTagFlow();
        } else {
          this.props.onSelect([selectedTagValue], info);
          this.setState({visible: false});
        }
      } else if (!isLeaf) {
        this.handleOnExpand(selectedKeys[0]);
      }
    }
  };

  handleOnExpand = (key) => {
    const expandedKeys = this.state.expandedKeys.slice();
    const index = _.indexOf(expandedKeys, key);
    if (index !== -1) {
      expandedKeys.splice(index, 1);
    } else {
      expandedKeys.push(key);
    }
    this.setState({expandedKeys, autoExpandParent: false});
  };

  togglePopoverVisibility = (visible) => {
    this.setState({visible});
    // Call onVisibleChange callback if provided (for triggering API calls when popover opens)
    if (this.props.onVisibleChange) {
      this.props.onVisibleChange(visible);
    }
  };

  renderDynamicTagFlow = () => {
    this.setState({showModal: true, visible: false});
  };

  renderTags = (tags, parentPath = '') => {
    const searchString = this.state.searchValue || '';
    const {
      disableRelatedTags, childTagsToDisable, parentTagstoDisable,
    } = this?.props?.disableTagsDetails;
    const { accessibleFeatures = [] } = this?.props?.currentOrgDetails || {};
    const hideDateTagsForJpLocale = accessibleFeatures.includes(JP_LOCALE_HIDE_FEATURE);
    const list = [];
    const loyaltyAttrDisableText = <FormattedMessage {...messages.loyaltyAttributeDisable} />;
    const customerBarcodeDisableText = <FormattedMessage {...messages.customerBarcodeDisable} />;
    let clonedTags = _.cloneDeep(tags);
    if (!hasCardBasedScope()) {
      clonedTags = _.omit(clonedTags, CARD_RELATED_TAGS);
    }
    if (!hasHospitalityBasedScope()) {
      //filtering HOSPITALITY_RELATED_TAGS if org does not have HOSPITALITY_BASED_SCOPE feature enabled
      clonedTags = _.omit(clonedTags, HOSPITALITY_RELATED_TAGS);
    }
    if (!hasCustomerBarcodeFeatureEnabled()) {
      //filtering CUSTOMER_BARCODE_TAG if org does not have CUSTOMER_BARCODE_TAG feature enabled
      clonedTags = _.omit(clonedTags, CUSTOMER_BARCODE_TAG);
    }
    _.forEach(clonedTags, (val = '', key) => {
      const rawKey = val?.incentiveSeriesId ? `${key}(${val?.incentiveSeriesId})` : `${key}`;
      const nodeKey = parentPath ? `${parentPath}.${rawKey}` : rawKey;
      let supportedTagsString = '';
      _.forEach(val.supportedTags, (supportedTag) => {
        supportedTagsString += `${supportedTag} ,`;
      });
      supportedTagsString = supportedTagsString.replace(/,\s*$/, "");
      const tagName =
        typeof val?.name === 'string'
          ? _.toLower(_.get(val, "name", ""))
          : _.toLower(_.get(val, "name.props.defaultMessage", ""));
      const tagNameWithoutUnderscore = tagName.replace(/_/g, " ");
      const searchStringLower = _.toLower(searchString);
      const tagContainsSearchedString = searchStringLower
        && (tagName.includes(searchStringLower)
          || tagNameWithoutUnderscore.includes(searchStringLower));
      if (_.has(val, 'subtags')) {
        const disabled = disableRelatedTags ? parentTagstoDisable.includes(key) : false;
        const temp = this.renderTags(val?.subtags, nodeKey);
        if (temp?.length) {
          const node = {
            title: disabled ? <CapTooltip title={loyaltyAttrDisableText}>{val?.name}</CapTooltip> : val?.name,
            key: nodeKey,
            tag: val,
            tagKey: rawKey,
            disabled,
            children: temp,
          };
          hidingDateTagsForJpLocale(hideDateTagsForJpLocale, val, list, node);
        }
      } else {
        let childDisabled = true;
        if (key === CUSTOMER_BARCODE_TAG && !hasCustomerBarcodeFeatureEnabled()) {
          childDisabled = true;
        } else {
          childDisabled = disableRelatedTags ? childTagsToDisable.includes(key) : false;
        }
        const leafTitle = childDisabled ? (
          <CapTooltip
            title={key === CUSTOMER_BARCODE_TAG ? customerBarcodeDisableText : loyaltyAttrDisableText}
          >
            {val?.desc || val?.name}
          </CapTooltip>
        ) : (
          val?.desc || val?.name
        );
        const leafNode = {
          title: leafTitle,
          key: nodeKey,
          tag: val,
          tagKey: rawKey,
          isLeaf: true,
          disabled: childDisabled,
        };
        if (searchString) {
          if (tagContainsSearchedString) {
            hidingDateTagsForJpLocale(hideDateTagsForJpLocale, val, list, leafNode);
          }
        } else {
          hidingDateTagsForJpLocale(hideDateTagsForJpLocale, val, list, leafNode);
        }
      }
    });
    return list;
  }

  openTranslationLink = () => {
    window.open(TAG_TRANSLATION_DOC, '_blank');
  }

  render() {
    const {
      hidePopover = false, intl = {}, moduleFilterEnabled, label, modalProps, channel, fetchingSchemaError = false,
    } = this.props;
    const {formatMessage} = intl;
    const {
      tagValue, selectedNodeKey, expandedKeys, autoExpandParent, visible, translationLang, selectedContext, isLoadingLoyaltyTags, isLoadingContextChange,
    } = this.state;

    // Show loading spinner if general loading OR if specifically loading loyalty tags OR if context change is in progress
    const shouldShowLoading = this.props.loading || (selectedContext === LOYALTY && isLoadingLoyaltyTags) || isLoadingContextChange;

    const options = [
      {
        value: "Outbound",
        label: formatMessage(messages.Standard),
        key: 'outbound',
      },
      {
        value: "Loyalty",
        label: formatMessage(messages.loyalty),
        key: 'loyalty',
      },
    ];
    const contentSection = (
      <CapRow useLegacy className="cap-tag-list-popover-inner">
        <CapSpin tip={formatMessage(messages.gettingTags)} spinning={shouldShowLoading}>
          <Search
            style={{ marginBottom: 8, width: '250px'}}
            placeholder={formatMessage(messages.search)}
            onChange={this.onChange} />
          {moduleFilterEnabled ? (
            <CapSelect
              getPopupContainer={(triggerNode) => triggerNode.parentNode}
              style={{
                width: '250px', marginBottom: '16px', minWidth: 'initial', display: 'flex',
              }}
              onChange={this.handleOnChange}
              value={selectedContext}
              options={options}>
            </CapSelect>
          ) : ''}
          <CapTree
            style={{height: '350px', overflow: 'auto'}}
            treeData={this.state.tagsList}
            onSelect={this.handleOnSelect}
            selectedKeys={selectedNodeKey ? [selectedNodeKey] : []}
            expandedKeys={expandedKeys}
            autoExpandParent={autoExpandParent}
            onExpand={this.onExpand}
          />
          {translationLang === "ja-JP" && (
            <div className="tag-list-footer">
              <CapIcon
                type="help"
                size="s"
              />
              <CapLink>
                <CapButton id="translationtagfooter" type="link" onClick={this.openTranslationLink}>
                  <div className="tag-list-footer-icon">
                    <div>{JAPANESE_HELP_TEXT}</div>
                    <CapIcon
                      type="open-in-new-light"
                      size="s"
                      svgProps={{ color: FONT_COLOR_05 }}
                    />
                  </div>
                </CapButton>
              </CapLink>
            </div>
          )}

        </CapSpin>
      </CapRow>
    );
    const {disableTooltipMsg, disabled} = this.props || {};
    return (
      <>
        {hidePopover ? (
          <CapModal
            visible={this.props.visibleTaglist}
            footer={[]}
            {...modalProps}
          >
            {contentSection}
          </CapModal>
        ) : (
          <CapPopover
            visible={fetchingSchemaError ? false : visible}
            onVisibleChange={this.togglePopoverVisibility}
            content={contentSection}
            trigger="click"
            placement={this.props.popoverPlacement || (channel === EMAIL.toUpperCase() ? "leftTop" : "rightTop")}
            classNames={{
              container: 'tag-list-popover-container'
            }}
          >
            <CapTooltip
              title={
                disableTooltipMsg && disabled ? (
                  disableTooltipMsg
                ) : fetchingSchemaError ? (
                  <CapRow useLegacy className="tooltip-text-container">
                    <CapLabel className="tooltip-text1">
                      {formatMessage(messages.somethingWentWrong)}
                    </CapLabel>
                    <CapLabel className="tooltip-text2">
                      {formatMessage(messages.labelFetchErrorMsg)}
                    </CapLabel>
                  </CapRow>
                ) : null
              }
              placement="right"
            >
              <CapRow useLegacy className="tooltip-add-label-container">
                <CapButton
                  disabled={
                    this?.props?.disabled || fetchingSchemaError
                  }
                  isAddBtn
                  type="flat"
                >
                  {label || ""}
                </CapButton>
              </CapRow>
            </CapTooltip>
          </CapPopover>
        )}
        <CapModal
          visible={this.state.showModal}
          title={this.props.intl.formatMessage(messages["Dynamic Days before Expiry"])}
          onOk={this.handleOk}
          onCancel={this.handleCancel}
          footer={[
            <CapButton key="back" onClick={this.handleCancel}>{this.props.intl.formatMessage(messages.Cancel)}</CapButton>,
            <CapButton key="submit" type="primary" id="delete-version" onClick={this.handleOk}>
              {this.props.intl.formatMessage(messages.Ok)}
            </CapButton>,
          ]}
        >
          <p>{this.props.intl.formatMessage(messages.numberOfDaysBeforeExpiry)}</p>
          <CapInput onChange={this.handleDynamicDateChange} value={this.state.dynamicDateValue} size="default"></CapInput>
        </CapModal>
      </>
    );
  }
}

CapTagList.propTypes = {
  tags: PropTypes.object,
  onSelect: PropTypes.func,
  label: PropTypes.string,
  onContextChange: PropTypes.func,
  loading: PropTypes.bool,
  moduleFilterEnabled: PropTypes.bool,
  intl: intlShape.isRequired,
  visibleTaglist: PropTypes.bool,
  hidePopover: PropTypes.bool,
  modalProps: PropTypes.any,
  disableTagsDetails: PropTypes.object,
  currentOrgDetails: PropTypes.object,
  channel: PropTypes.string,
  disabled: PropTypes.bool,
  // Optional custom tooltip message when disabled (used for personalization restriction)
  disableTooltipMsg: PropTypes.string,
  fetchingSchemaError: PropTypes.bool,
  popoverPlacement: PropTypes.string,
};

CapTagList.defaultValue = {
  hidePopover: false,
};

function mapDispatchToProps() {
  return {
  };
}

const mapStateToProps = createStructuredSelector({
  disableTagsDetails: makeSelectLoyaltyPromotionDisplay(),
});


export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(CapTagList));
