import React, {
  useState, useEffect, useMemo, useCallback, useRef, useImperativeHandle, forwardRef,
} from 'react';
import PropTypes from 'prop-types';
import { injectIntl, FormattedMessage } from 'react-intl';
import isEmpty from 'lodash/isEmpty';
import get from 'lodash/get';
import _ from 'lodash';
import { CAP_SPACE_16 } from '@capillarytech/cap-ui-library/styled/variables';
import CapSpin from '@capillarytech/cap-ui-library/CapSpin';
import CapRow from '@capillarytech/cap-ui-library/CapRow';
import CapColumn from '@capillarytech/cap-ui-library/CapColumn';
import CapNotification from '@capillarytech/cap-ui-library/CapNotification';
import HTMLEditor from '../../../v2Components/HtmlEditor';
import CapTagListWithInput from '../../../v2Components/CapTagListWithInput';
import formBuilderMessages from '../../../v2Components/FormBuilder/messages';
import { validateLiquidTemplateContent } from '../../../utils/commonUtils';
import { isEmailUnsubscribeTagOptional } from '../../../utils/common';
import history from '../../../utils/history';
import messages from '../messages';
import emailMessages from '../../Email/messages';
import { validateTags } from '../../../utils/tagValidations';
import {
  TAG, EMBEDDED, DEFAULT, FULL, LIBRARY,
} from '../../Whatsapp/constants';
import { EMAIL } from '../../CreativesContainer/constants';
import { OUTBOUND } from '../../../v2Components/FormBuilder/constants';

/**
 * EmailHTMLEditor Component
 *
 * IMPORTANT: This component is ONLY used when supportCKEditor flag is FALSE (new flow).
 * When supportCKEditor is TRUE, the existing Email component with FormBuilder is used (legacy flow).
 *
 * A completely self-contained component for Email HTML Editor that handles:
 * - Tag loading and management
 * - Tag validation
 * - Content editing with HTMLEditor
 * - Template data extraction for edit mode
 * - Save logic (full mode & library mode) with liquid validation
 * - API calls via Email actions/sagas
 *
 * This component is independent and reusable, similar to Whatsapp and InApp channels.
 */
const EmailHTMLEditor = (props) => {
  const {
    intl,
    location,
    params,
    getDefaultTags,
    supportedTags,
    metaEntities,
    injectedTags,
    globalActions,
    loadingTags,
    eventContextTags,
    waitEventContextTags,
    forwardedTags,
    selectedOfferDetails,
    currentOrgDetails,
    isReadOnly = false,
    fetchingLiquidTags = false,
    createTemplateInProgress = false,
    fetchingCmsData = false,
    // Email Redux state
    Email,
    // Email actions for API calls
    emailActions,
    // Full mode props
    isFullMode,
    templateName,
    showTemplateName,
    isGetFormData,
    getFormdata,
    // Library mode props
    templateData: templateDataProp,
    isEditEmail = true,
    // Uploaded content from zip file
    EmailLayout,
    // Liquid validation
    getLiquidTags,
    showLiquidErrorInFooter,
    onValidationFail,
    // Preview/Test
    // Parent loading control
    setIsLoadingContent,
    forwardedRef,
    // Module type for unsubscribe tag validation
    moduleType,
    // Validation state callback
    onHtmlEditorValidationStateChange,
  } = props;

  const { formatMessage } = intl;

  // State for content and subject
  const [htmlContent, setHtmlContent] = useState('');
  const [loadedHtmlContent, setLoadedHtmlContent] = useState(''); // Stable content for HTMLEditor initialization
  const [subject, setSubject] = useState('');
  const [subjectError, setSubjectError] = useState('');
  // State for template name (extracted from template data in Edit mode)
  const [extractedTemplateName, setExtractedTemplateName] = useState('');
  const [tagValidationError, setTagValidationError] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  const [errorsAcknowledged, setErrorsAcknowledged] = useState(false); // Track if user has acknowledged errors by clicking redirection icon
  // State for API validation errors (from validateLiquidTemplateContent)
  const [apiValidationErrors, setApiValidationErrors] = useState({
    liquidErrors: [],
    standardErrors: [],
  });

  // Merge tag validation errors (missing) into apiValidationErrors so they show in ValidationErrorDisplay
  const mergedApiValidationErrors = useMemo(() => {
    const tagMessages = [];
    if (tagValidationError?.missingTags?.length && !isEmailUnsubscribeTagOptional()) {
      tagMessages.push(`Missing tags are: ${tagValidationError.missingTags.join(', ')}`);
    }
    if (tagMessages.length === 0) {
      return apiValidationErrors;
    }
    return {
      liquidErrors: apiValidationErrors?.liquidErrors || [],
      standardErrors: [...(apiValidationErrors?.standardErrors || []), ...tagMessages],
    };
  }, [apiValidationErrors, tagValidationError]);

  // Refs for tracking initialization and previous values
  const contentInitializedRef = useRef(false);
  const subjectInitializedRef = useRef(false);
  const lastTemplateIdRef = useRef(null);
  const fetchingTemplateIdRef = useRef(null); // Track which template we're currently fetching
  const prevIsGetFormDataRef = useRef(false);
  const prevErrorCountRef = useRef(0); // Track previous error count to detect new errors
  const handleSaveRef = useRef(null);

  // Ref to HTMLEditor to access validation state
  const htmlEditorRef = useRef(null);

  // Compute tags directly from metaEntities (same approach as Email component)
  // Use deep equality check to prevent TagList from re-processing when tags haven't actually changed
  // This fixes the slow expansion and React Intl errors when clicking nested tags
  const tags = useMemo(() => {
    let tagList = get(metaEntities, 'tags.standard', []);
    const { type, module } = location?.query || {};
    if (type === EMBEDDED && module === LIBRARY && !getDefaultTags) {
      tagList = supportedTags || [];
    }
    return tagList;
  }, [metaEntities, supportedTags, location, getDefaultTags]);

  // Expose method to get formData for TestAndPreviewSlidebox
  useImperativeHandle(forwardedRef, () => ({
    getFormDataForPreview: () => {
      const baseLanguage = get(currentOrgDetails, 'basic_details.base_language', 'en');
      return {
        "0": {
          [baseLanguage]: {
            'template-content': htmlContent || '',
            'is_drag_drop': false,
          },
          activeTab: baseLanguage,
          selectedLanguages: [baseLanguage],
          base: true,
        },
        'template-subject': subject || '',
      };
    },
    getContentForPreview: () => htmlContent || '',
    getValidationState: () => {
      if (htmlEditorRef.current && htmlEditorRef.current.getValidation) {
        return htmlEditorRef.current.getValidation();
      }
      return null;
    },
    isContentEmpty: () => {
      if (htmlEditorRef.current && htmlEditorRef.current.isContentEmpty) {
        return htmlEditorRef.current.isContentEmpty();
      }
      return !htmlContent || htmlContent.trim() === '';
    },
    getIssueCounts: () => {
      if (htmlEditorRef.current && htmlEditorRef.current.getIssueCounts) {
        return htmlEditorRef.current.getIssueCounts();
      }
      return {
        html: 0, label: 0, liquid: 0, total: 0,
      };
    },
  }), [htmlContent, subject, currentOrgDetails]);

  // Detect edit mode: when isEditEmail is false (create flow), never treat as edit or fetch template details
  const hasParamsId = params?.id || location?.query?.id || location?.params?.id || location?.pathname?.includes('/edit/');
  const currentTemplateId = isEditEmail
    ? (templateDataProp?._id || params?.id || location?.query?.id || location?.params?.id
      || location?.pathname?.match(/\/edit\/([^/]+)/)?.[1])
    : (params?.id || location?.query?.id || location?.params?.id || location?.pathname?.match(/\/edit\/([^/]+)/)?.[1]);
  const isEditMode = isEditEmail && (!!currentTemplateId || !!hasParamsId);

  // Load tags on component mount
  useEffect(() => {
    const { type, module } = location?.query || {};
    const isEmbedded = type === EMBEDDED;
    const query = {
      layout: EMAIL,
      type: TAG,
      context: isEmbedded ? module : DEFAULT,
      embedded: isEmbedded ? type : FULL,
    };
    if (getDefaultTags) {
      query.context = getDefaultTags;
    }
    if (globalActions && globalActions.fetchSchemaForEntity) {
      globalActions.fetchSchemaForEntity(query);
    }
  }, []);

  // Initialize content from EmailLayout (uploaded zip) in create mode
  useEffect(() => {
    // Only check EmailLayout in create mode (not edit mode)
    if (isEditMode) {
      return;
    }

    // Check if EmailLayout has content from zip upload
    if (EmailLayout) {
      // EmailLayout can be a string (HTML content) or an object with html property
      const uploadedContent = typeof EmailLayout === 'string'
        ? EmailLayout
        : (EmailLayout.html || EmailLayout.content || '');

      if (uploadedContent) {
        // IMPORTANT: Set both htmlContent and loadedHtmlContent for ZIP upload
        // loadedHtmlContent is used by HTMLEditor's initialContent prop
        setHtmlContent(uploadedContent);
        setLoadedHtmlContent(uploadedContent);
        setIsLoading(false);
        if (setIsLoadingContent) {
          setIsLoadingContent(false);
        }
      } else {
        // No uploaded content, stop loading
        setIsLoading(false);
        if (setIsLoadingContent) {
          setIsLoadingContent(false);
        }
      }
    } else {
      // No EmailLayout, stop loading
      setIsLoading(false);
      if (setIsLoadingContent) {
        setIsLoadingContent(false);
      }
    }
  }, [EmailLayout, isEditMode, setIsLoadingContent]);

  // Edit mode: Extract template data and load content/subject
  useEffect(() => {
    if (!isEditMode) {
      // Create mode: stop loading immediately
      setIsLoading(false);
      return;
    }

    const templateDataFromRedux = Email?.templateDetails || Email?.BEETemplate;
    const isTemplateLoading = Email?.getTemplateDetailsInProgress || Email?.fetchingCmsData;

    // Check if template ID changed (switching templates)
    const templateIdChanged = currentTemplateId
      && lastTemplateIdRef.current
      && currentTemplateId !== lastTemplateIdRef.current;

    // Reset refs when switching templates
    if (templateIdChanged) {
      contentInitializedRef.current = false;
      subjectInitializedRef.current = false;
      lastTemplateIdRef.current = currentTemplateId;
      setHtmlContent('');
      setSubject('');
      setExtractedTemplateName('');
    }

    // Set last template ID on first load
    if (currentTemplateId && !lastTemplateIdRef.current) {
      lastTemplateIdRef.current = currentTemplateId;
    }

    // Check if templateDataProp has complete data
    // Check if templateDataProp has complete data (must have actual content string)
    const hasCompleteTemplateData = templateDataProp && (
      (templateDataProp.emailBody || templateDataProp.html_content || templateDataProp['template-content'])
      || (templateDataProp.base && (templateDataProp.base.html_content || templateDataProp.base.emailBody || templateDataProp.base['template-content']))
      || (templateDataProp.versions?.base && (
        // Check active tab content in versions
        (() => {
          const { base } = templateDataProp.versions;
          const activeTab = base.activeTab || 'en';
          const langData = base[activeTab] || {};
          return langData['template-content'] || langData.html_content || base.html_content || base.emailBody;
        })()
      ))
    );
    if (hasCompleteTemplateData && !contentInitializedRef.current) {
      let extractedContent = '';
      let extractedSubject = '';
      let extractedName = '';

      if (templateDataProp.base) {
        extractedContent = templateDataProp.base['template-content'] || templateDataProp.base.html_content || templateDataProp.base.emailBody || '';
        extractedSubject = templateDataProp.base.subject || templateDataProp.base.emailSubject || '';
      } else if (templateDataProp.versions && templateDataProp.versions.base) {
        const { base } = templateDataProp.versions;
        const activeTab = base.activeTab || 'en';
        const languageData = base[activeTab] || {};

        extractedContent = languageData['template-content']
          || languageData.html_content
          || base.html_content
          || base.emailBody
          || '';

        extractedSubject = base.subject || base.emailSubject || '';
      } else {
        extractedContent = templateDataProp['template-content'] || templateDataProp.emailBody || templateDataProp.html_content || '';
        extractedSubject = templateDataProp.emailSubject || templateDataProp.subject || '';
      }

      // Extract template name from templateDataProp
      extractedName = templateDataProp.name || get(templateDataProp, 'versions.base.name') || '';

      // IMPORTANT: Set both htmlContent and loadedHtmlContent
      // loadedHtmlContent is used by HTMLEditor's initialContent prop
      setHtmlContent(extractedContent);
      setLoadedHtmlContent(extractedContent);
      setSubject(extractedSubject);
      setExtractedTemplateName(extractedName);
      contentInitializedRef.current = true;
      subjectInitializedRef.current = true;
      setIsLoading(false);
      if (setIsLoadingContent) {
        setIsLoadingContent(false);
      }
      return;
    }

    if (currentTemplateId && emailActions?.getTemplateDetails && !isTemplateLoading) {
      const isTemplateIdChanged = lastTemplateIdRef.current !== currentTemplateId;
      const needsContent = !contentInitializedRef.current;
      const alreadyFetching = fetchingTemplateIdRef.current === currentTemplateId;
      const shouldFetch = (isTemplateIdChanged || needsContent) && !alreadyFetching;

      // Fetch fresh data when template ID changes OR when we don't have content loaded yet
      // BUT only if we're not already fetching this template
      if (shouldFetch) {
        fetchingTemplateIdRef.current = currentTemplateId; // Mark as fetching
        emailActions.getTemplateDetails(currentTemplateId, 'email');
        lastTemplateIdRef.current = currentTemplateId;
      }
    }

    // **IMPORTANT: Clear stale Redux data in create mode**
    // When not in edit mode (create mode), clear any existing template data from Redux
    // This prevents previous template data from persisting when switching from Edit to Create
    if (!currentTemplateId && !isEditMode && (templateDataFromRedux?._id || templateDataFromRedux?.name)) {
      // Clear stale template data - component will handle via resetTemplateData or clearAllValues
      if (emailActions?.clearAllValues) {
        emailActions.clearAllValues();
      }
      // Reset component state to ensure clean slate for create mode
      setExtractedTemplateName('');
      contentInitializedRef.current = false;
      subjectInitializedRef.current = false;
      lastTemplateIdRef.current = null;
    }

    // Stop loading if template is loading
    if (isTemplateLoading) {
      return;
    }

    // Extract from Redux data
    const hasTemplateDataFromRedux = templateDataFromRedux
      && (templateDataFromRedux._id || templateDataFromRedux.name || templateDataFromRedux.versions);

    if (hasTemplateDataFromRedux && currentTemplateId) {
      const reduxTemplateId = templateDataFromRedux?._id;

      if (reduxTemplateId === currentTemplateId) {
        const baseData = get(templateDataFromRedux, 'versions.base') || get(templateDataFromRedux, 'base') || {};
        const activeTab = baseData.activeTab
          || get(currentOrgDetails, 'basic_details.base_language', 'en');
        const languageData = baseData[activeTab] || {};

        const extractedContent = languageData['template-content']
          || languageData.html_content
          || baseData.html_content
          || baseData['template-content']
          || get(templateDataFromRedux, 'html_content')
          || get(templateDataFromRedux, 'template-content')
          || '';

        const extractedSubject = baseData.subject
          || get(templateDataFromRedux, 'subject')
          || get(templateDataFromRedux, 'versions.base.subject')
          || '';

        // Extract template name from Redux data
        const extractedName = templateDataFromRedux.name || '';

        // Smart update logic:
        // 1. Always update loadedHtmlContent if Redux data is different (keep sync with backend)
        // 2. Update htmlContent ONLY if it matches the OLD loadedHtmlContent (user hasn't edited)
        //    OR if it's the first initialization
        if (extractedContent !== loadedHtmlContent) {
          setLoadedHtmlContent(extractedContent);

          if (!contentInitializedRef.current || htmlContent === loadedHtmlContent) {
            setHtmlContent(extractedContent);
            setSubject(extractedSubject);
            setExtractedTemplateName(extractedName);
          }
        } else if (!contentInitializedRef.current) {
          // First load, even if content matches (e.g. empty), ensure we set state
          setHtmlContent(extractedContent);
          setLoadedHtmlContent(extractedContent);
          setSubject(extractedSubject);
          setExtractedTemplateName(extractedName);
        }

        contentInitializedRef.current = true;
        subjectInitializedRef.current = true;

        // Only clear fetching ref if we are not loading anymore
        // This prevents race conditions where we load stale data while real fetch is pending
        if (!isTemplateLoading) {
          fetchingTemplateIdRef.current = null;
        }
      }

      setIsLoading(false);
      if (setIsLoadingContent) {
        setIsLoadingContent(false);
      }
      return;
    }

    // Fallback: stop loading anyway
    if (!isTemplateLoading && !hasTemplateDataFromRedux && !hasCompleteTemplateData) {
      setHtmlContent('');
      setLoadedHtmlContent(''); // Set stable loaded content
      setSubject('');
      setExtractedTemplateName('');
      setIsLoading(false);
      if (setIsLoadingContent) {
        setIsLoadingContent(false);
      }
    }
  }, [
    Email?.templateDetails,
    Email?.BEETemplate,
    Email?.getTemplateDetailsInProgress,
    Email?.fetchingCmsData,
    templateDataProp,
    currentTemplateId,
    isEditMode,
    emailActions,
    currentOrgDetails,
  ]);

  // Handle loading state
  useEffect(() => {
    const isAnyApiInProgress = loadingTags || fetchingLiquidTags || createTemplateInProgress || fetchingCmsData;

    // Stop loading when no API is in progress and tags are loaded
    // Use optional chaining to safely access tags
    if (!isAnyApiInProgress && Array.isArray(tags) && tags?.length >= 0) {
      setIsLoading(false);
    } else if (isAnyApiInProgress) {
      setIsLoading(true);
    }
  }, [loadingTags, tags, fetchingLiquidTags, createTemplateInProgress, fetchingCmsData]);

  // Handle content change from HTMLEditor
  const handleContentChange = useCallback((content) => {
    setHtmlContent(content);

    // Clear previous liquid/API validation errors so Done button can be enabled after user fixes content
    setApiValidationErrors({
      liquidErrors: [],
      standardErrors: [],
    });
    if (showLiquidErrorInFooter) {
      showLiquidErrorInFooter({
        STANDARD_ERROR_MSG: [],
        LIQUID_ERROR_MSG: [],
      });
    }

    // Validate tags
    if (tags.length > 0 || !isEmpty(injectedTags)) {
      const validationResult = validateTags({
        content,
        tagsParam: tags,
        location,
        tagModule: getDefaultTags,
        isFullMode,
      });

      if (!validationResult.valid) {
        setTagValidationError(validationResult);
      } else {
        setTagValidationError(null);
      }
    }
  }, [tags, injectedTags, location, getDefaultTags, eventContextTags, waitEventContextTags, showLiquidErrorInFooter]);

  // Store the last validation state received from HTMLEditor
  const lastValidationStateRef = useRef(null);

  // Use ref to store callback to avoid infinite loops (callback in deps would cause re-runs)
  const onValidationStateChangeRef = useRef(onHtmlEditorValidationStateChange);
  useEffect(() => {
    onValidationStateChangeRef.current = onHtmlEditorValidationStateChange;
  }, [onHtmlEditorValidationStateChange]);

  // Handle error acknowledgment - called when user clicks redirection icon
  const handleErrorAcknowledged = useCallback(() => {
    setErrorsAcknowledged(true);
    // Immediately update parent with acknowledged state
    if (onValidationStateChangeRef.current && lastValidationStateRef.current) {
      onValidationStateChangeRef.current({
        ...lastValidationStateRef.current,
        errorsAcknowledged: true,
      });
    }
  }, []); // No deps needed - using ref

  // Track last sent state to parent to prevent duplicate updates
  const lastSentToParentRef = useRef(null);

  // Callback to receive validation state from HTMLEditor
  const handleValidationChange = useCallback((validationState) => {
    const {
      isContentEmpty, issueCounts, validationComplete, hasErrors,
    } = validationState;
    const currentErrorCount = issueCounts?.total || 0;

    // Reset acknowledgment when new errors appear
    let shouldAcknowledgeErrors = errorsAcknowledged;
    if (hasErrors && validationComplete) {
      const isFirstTimeErrors = prevErrorCountRef.current === 0 || prevErrorCountRef.current === undefined;
      const errorCountChanged = currentErrorCount !== prevErrorCountRef.current;

      if (isFirstTimeErrors || (errorCountChanged && currentErrorCount > 0)) {
        setErrorsAcknowledged(false);
        shouldAcknowledgeErrors = false;
      }
    } else if (!hasErrors && validationComplete) {
      // No errors - allow buttons to be enabled
      prevErrorCountRef.current = 0;
      shouldAcknowledgeErrors = true;
    }

    // Update previous error count
    if (validationComplete) {
      prevErrorCountRef.current = currentErrorCount;
    }

    // Store last validation state (hasErrors = Rule Group #1 only, for save gating)
    lastValidationStateRef.current = {
      isContentEmpty,
      issueCounts,
      validationComplete,
      hasErrors: hasErrors === true,
    };

    // Notify parent about validation state (using ref to avoid infinite loops)
    // hasErrors = only Rule Group #1 (Input & Sanitization) – used by SlideBoxFooter for button gating
    if (onValidationStateChangeRef.current) {
      const newState = {
        isContentEmpty,
        issueCounts,
        validationComplete,
        hasErrors: hasErrors === true,
        errorsAcknowledged: hasErrors ? shouldAcknowledgeErrors : true,
      };

      const lastState = lastSentToParentRef.current;
      const hasChanged = !lastState
        || lastState.isContentEmpty !== newState.isContentEmpty
        || lastState.validationComplete !== newState.validationComplete
        || lastState.hasErrors !== newState.hasErrors
        || lastState.errorsAcknowledged !== newState.errorsAcknowledged
        || lastState.issueCounts?.total !== newState.issueCounts?.total;

      if (hasChanged) {
        lastSentToParentRef.current = newState;
        onValidationStateChangeRef.current(newState);
      }
    }
  }, [errorsAcknowledged]);

  // Note: Initial validation state is now sent by HTMLEditor's onValidationChange callback
  // Removed the separate useEffect that was causing infinite loops by depending on htmlContent

  // Handle tag insertion into Subject field
  const handleSubjectTagSelect = useCallback((data) => {
    if (data) {
      const tagToInsert = `{{${data}}}`;
      const input = document.getElementById('template-subject') || document.querySelector('#template-subject input');
      let subjectValue = subject || '';
      try {
        if (input && (typeof input.selectionStart === 'number')) {
          const startPos = input.selectionStart;
          const endPos = input.selectionEnd;
          subjectValue = `${subjectValue.substring(0, startPos)}${tagToInsert}${subjectValue.substring(endPos)}`;
          setSubject(subjectValue);
          try {
            input.focus();
            const newPos = startPos + tagToInsert.length;
            input.selectionStart = newPos;
            input.selectionEnd = newPos;
          } catch (e) {
            // Ignore focus errors
          }
        } else {
          subjectValue = `${subjectValue}${tagToInsert}`;
          setSubject(subjectValue);
          if (input) {
            try {
              input.value = subjectValue;
            } catch (e) {
              // Ignore value setting errors
            }
          }
        }
      } catch (e) {
        // Fallback: safe append
        subjectValue = `${subjectValue}${tagToInsert}`;
        setSubject(subjectValue);
      }
    }
  }, [subject]);

  // Handle subject change
  const handleSubjectChange = useCallback((e) => {
    const newSubject = e.target.value;
    setSubject(newSubject);
    if (newSubject && subjectError) {
      setSubjectError('');
    }
  }, [subjectError]);

  // Handle Save/Update with liquid validation
  const handleSave = useCallback(() => {
    // IMPORTANT: Clear API validation errors FIRST before checking for validation errors
    // This ensures that old API errors don't block the save when user fixes content and clicks Update again
    // We'll re-validate with fresh API call anyway
    if (getLiquidTags) {
      setApiValidationErrors({
        liquidErrors: [],
        standardErrors: [],
      });
    }

    // 1. Validate Subject - BLOCKING (matches CK/BEE behavior)
    if (!subject || !subject.trim()) {
      const errorMessage = formatMessage(emailMessages["Email Subject cannot be empty."]);
      setSubjectError(errorMessage);
      // Reset parent state so next click is detected as a change
      if (onValidationFail) {
        onValidationFail();
      }
      // IMPORTANT: Return here to block save - matches CK/BEE editor behavior
      return;
    }
    // Clear error if subject is valid
    if (subjectError) {
      setSubjectError('');
    }

    // 1.5. Check for validation errors (Errors = blocking, Warnings = non-blocking)
    // Get issue counts from ref or stored state
    let issueCounts = { errors: 0, warnings: 0, total: 0 };
    if (htmlEditorRef.current && typeof htmlEditorRef.current.getIssueCounts === 'function') {
      issueCounts = htmlEditorRef.current.getIssueCounts();
    } else if (lastValidationStateRef.current?.issueCounts) {
      issueCounts = lastValidationStateRef.current.issueCounts;
    }

    // Only Rule Group #1 (Input & Sanitization) blocks save; warnings do not block
    // Check both lastValidationStateRef (from onValidationChange callback) and getValidationState (current state)
    const validationState = htmlEditorRef.current && typeof htmlEditorRef.current.getValidationState === 'function'
      ? htmlEditorRef.current.getValidationState()
      : null;
    const hasBlockingErrors = lastValidationStateRef.current?.hasErrors === true
      || (validationState && validationState.hasErrors === true);

    if (hasBlockingErrors) {
      setErrorsAcknowledged(false);
      if (onValidationStateChangeRef.current) {
        onValidationStateChangeRef.current({
          isContentEmpty: !htmlContent || !htmlContent.trim(),
          issueCounts,
          validationComplete: true,
          hasErrors: true,
          errorsAcknowledged: false,
        });
      }
      if (onValidationFail) {
        onValidationFail();
      }
      return;
    }

    // 2. Validate Unsubscribe Tag when feature is OFF (when flag is false we require unsubscribe)
    // When EMAIL_UNSUBSCRIBE_TAG_MANDATORY is true: do NOT validate for unsubscribe (aligned with FormBuilder).
    // When EMAIL_UNSUBSCRIBE_TAG_MANDATORY is false: validate and require unsubscribe tag.
    // Run for both library and full mode so liquid-enabled orgs also get the error (notification + ValidationErrorDisplay).
    const isModuleTypeOutbound = (moduleType || '').toUpperCase() === OUTBOUND;
    if (!isEmailUnsubscribeTagOptional() && isModuleTypeOutbound) {
      const unsubscribeRegex = /{{unsubscribe(\(#[a-zA-Z\d]{6}\))?}}/g; // eslint-disable-line no-useless-escape
      const hasUnsubscribeTag = unsubscribeRegex.test(htmlContent);

      if (!hasUnsubscribeTag) {
        setTagValidationError({ valid: false, missingTags: ['unsubscribe'] });
        const missingTagsMsg = intl.formatMessage(formBuilderMessages.missingTags);
        const errorMessage = `${missingTagsMsg} unsubscribe`;
        setTimeout(() => {
          CapNotification.error({
            message: 'ERROR ! ! !',
            description: errorMessage,
            duration: 5,
          });
        }, 0);

        if (onValidationFail) {
          onValidationFail();
        }
        return;
      }
    }

    // 3. Validate Content Tags
    // For NON-liquid orgs: BLOCKING validation (matches CK/BEE behavior)
    // For liquid orgs: Non-blocking (extractTags API will validate)
    // In library mode, always validate when there is content (even if tags list is empty)
    const shouldValidateTags = (tags.length > 0 || !isEmpty(injectedTags)) || (!isFullMode && !!htmlContent);
    if (shouldValidateTags) {
      const validationResult = validateTags({
        content: htmlContent,
        tagsParam: tags,
        location,
        tagModule: getDefaultTags,
        isFullMode,
      });

      if (!validationResult?.valid) {
        setTagValidationError(validationResult);
        // For liquid orgs, show warning and continue (extractTags API will validate)
      }
      // Clear tag errors if valid
      if (tagValidationError && validationResult?.valid) {
        setTagValidationError(null);
      }
    }


    const baseLanguage = get(currentOrgDetails, 'basic_details.base_language', 'en');

    // Actual save function - called after liquid validation (if enabled) or directly
    const performSave = () => {
      if (isFullMode) {
        // Full mode: Call email actions directly
        const templateDataFromRedux = Email?.templateDetails || Email?.BEETemplate;
        // IMPORTANT: Only use currentTemplateId from URL/params - don't fallback to Redux data
        // which might be stale from previous template in create mode
        const templateId = currentTemplateId;
        const isEditModeForSave = !!templateId;

        const langId = get(currentOrgDetails, `basic_details.languages.${baseLanguage}.lang_id`, '');
        const language = get(currentOrgDetails, `basic_details.languages.${baseLanguage}.language`, baseLanguage);

        // Generate or reuse tabKey
        let tabKey = _.uniqueId();
        if (isEditMode && templateDataFromRedux) {
          const existingTabKey = get(templateDataFromRedux, 'versions.base.tabKey')
            || get(templateDataFromRedux, 'base.tabKey');
          if (existingTabKey) {
            tabKey = existingTabKey;
          }
        }

        const languageData = {
          'template-content': htmlContent || '',
          "is_drag_drop": false,
          "drag_drop_id": '',
          "lang_id": langId,
          "iso_code": baseLanguage,
          "language": language,
          "tabKey": tabKey,
        };

        const baseStructure = {
          [baseLanguage]: languageData,
          activeTab: baseLanguage,
          selectedLanguages: [baseLanguage],
          base: true,
          tabKey,
          subject: subject || '',
        };

        const historyEntry = {
          [baseLanguage]: { ...languageData },
          activeTab: baseLanguage,
          selectedLanguages: [baseLanguage],
          base: true,
          tabKey,
          subject: subject || '',
        };

        const finalTemplateName = isEditModeForSave ? (extractedTemplateName || '') : (templateName || '');

        const obj = {
          type: EMAIL,
          // In Edit mode, use extractedTemplateName; in Create mode, use templateName prop
          name: finalTemplateName,
          versions: {
            base: baseStructure,
            history: [historyEntry],
          },
        };

        if (isEditModeForSave && templateId) {
          obj._id = templateId;
        }

        if (emailActions?.transformEmailTemplate && emailActions?.createTemplate) {
          emailActions.transformEmailTemplate(obj, (newEmail) => {
            emailActions.createTemplate(newEmail, (createResponse) => {
              // Handle error response (from 409 or other failures)
              if (createResponse?.error) {
                // Error already shown by Email component via stopValidation
                // Reset acknowledgment so buttons are disabled again
                setErrorsAcknowledged(false);
                // Just reset parent state so next click is detected
                if (onValidationFail) {
                  onValidationFail();
                }
                return;
              }

              // Handle success response
              if (createResponse && createResponse.templateId) {
                const successMessage = formatMessage(
                  isEditModeForSave ? emailMessages.emailEditSuccess : emailMessages.emailCreateSuccess
                );
                CapNotification.success({
                  message: successMessage,
                  key: isEditModeForSave ? 'edit-template-success' : 'create-template-success',
                });

                const module = location?.query?.module || 'default';
                const type = location?.query?.type;
                const isLanguageSupport = location?.query?.isLanguageSupport || false;
                const isBEESupport = (location?.query?.isBEESupport !== "false") || false;

                if (getFormdata) {
                  const { versions, ...rest } = createResponse.templateId;
                  getFormdata({ value: versions, ...rest, validity: true });
                } else {
                  const queryParams = type === 'embedded'
                    ? {
                      type: 'embedded', module, isLanguageSupport, isBEESupport,
                    }
                    : { module, isLanguageSupport, isBEESupport };

                  const searchParams = new URLSearchParams();
                  Object.keys(queryParams).forEach((key) => {
                    if (queryParams[key] !== undefined && queryParams[key] !== null) {
                      searchParams.append(key, queryParams[key]);
                    }
                  });

                  history.push({
                    pathname: '/email',
                    search: searchParams.toString() ? `?${searchParams.toString()}` : '',
                  });
                }
              }
            });
          });
        }
      } else {
        // Library mode: Use getFormdata flow
        const tmpData = {
          html_content: htmlContent || '',
          is_drag_drop: false,
          lang_id: get(currentOrgDetails, `basic_details.languages.${baseLanguage}.lang_id`, ''),
          iso_code: baseLanguage,
          language: get(currentOrgDetails, `basic_details.languages.${baseLanguage}.language`, baseLanguage),
        };

        const libraryPayload = {
          base: tmpData,
          secondary_templates: [{ template_data: tmpData }],
        };
        libraryPayload.base.subject = subject || '';

        if (location?.query?.module === 'library' && isGetFormData && getFormdata) {
          const response = {
            action: "getFormData",
            postAction: 'next',
            id: get(Email, 'templateDetails._id', ''),
            value: libraryPayload,
            validity: true,
            type: EMAIL,
          };
          getFormdata(response);
        } else if (getFormdata) {
          getFormdata({
            value: libraryPayload,
            validity: true,
            type: EMAIL,
          });
        }
      }
    };

    // Liquid validation (extractTags) only in library mode
    if (getLiquidTags && !isFullMode) {
      const onError = ({ standardErrors, liquidErrors }) => {
        setApiValidationErrors({
          liquidErrors: liquidErrors || [],
          standardErrors: standardErrors || [],
        });

        if (showLiquidErrorInFooter) {
          showLiquidErrorInFooter({
            STANDARD_ERROR_MSG: standardErrors || [],
            LIQUID_ERROR_MSG: liquidErrors || [],
          });
        }
        if (onValidationFail) {
          onValidationFail();
        }
      };

      const onSuccess = () => {
        setApiValidationErrors({
          liquidErrors: [],
          standardErrors: [],
        });
        performSave();
      };

      validateLiquidTemplateContent(htmlContent || '', {
        getLiquidTags: getLiquidTags
          ? (inputContent, callback) => getLiquidTags(inputContent, callback)
          : (inputContent, callback) => globalActions?.getLiquidTags?.(inputContent, callback),
        formatMessage: intl.formatMessage,
        messages: formBuilderMessages,
        onError,
        onSuccess,
      });
    } else {
      performSave();
    }
  }, [
    subject,
    htmlContent,
    tags,
    injectedTags,
    location,
    getDefaultTags,
    formatMessage,
    subjectError,
    isFullMode,
    currentOrgDetails,
    Email,
    currentTemplateId,
    templateDataProp,
    templateName,
    emailActions,
    getFormdata,
    isGetFormData,
    getLiquidTags,
    showLiquidErrorInFooter,
    globalActions,
    intl,
    extractedTemplateName,
  ]);

  // Keep handleSave ref up to date - MUST be before isGetFormData effect
  useEffect(() => {
    handleSaveRef.current = handleSave;
  }, [handleSave]);

  // Trigger save when isGetFormData becomes true (Create/Done button clicked)
  useEffect(() => {
    const isGetFormDataChanged = isGetFormData && !prevIsGetFormDataRef.current;
    const wasReset = !isGetFormData && prevIsGetFormDataRef.current;

    if (isGetFormDataChanged) {
      // Update ref immediately to prevent duplicate calls
      prevIsGetFormDataRef.current = true;
      // Call handleSave via ref to ensure we're using the latest version
      // This avoids the effect re-running when handleSave changes
      if (handleSaveRef.current) {
        handleSaveRef.current();
      } else {
        console.warn('[EmailHTMLEditor] handleSaveRef.current is null!');
      }
    } else if (wasReset) {
      // Reset ref when parent resets isGetFormData (e.g., after validation failure)
      prevIsGetFormDataRef.current = false;
    } else {
      // Update ref to current value for next comparison
      prevIsGetFormDataRef.current = isGetFormData;
    }
  }, [isGetFormData, isEditMode]); // Include isEditMode for logging

  // Handle tag context change
  const handleOnTagsContextChange = useCallback((data) => {
    const { type, module } = location?.query || {};
    const isEmbedded = type === EMBEDDED;
    const contextValue = data || (isEmbedded ? module : DEFAULT);
    const query = {
      layout: EMAIL,
      type: TAG,
      context: contextValue ? contextValue.toLowerCase() : contextValue,
      embedded: isEmbedded ? type : FULL,
    };
    if (globalActions && globalActions.fetchSchemaForEntity) {
      globalActions.fetchSchemaForEntity(query);
    }
  }, [location, globalActions]);


  const spinTip = fetchingLiquidTags ? <FormattedMessage {...formBuilderMessages.liquidSpinText} /> : '';

  // Handle template name change
  // Call showTemplateName when templateName is available (for CreativesContainer header)
  // This matches the behavior of Email component which calls showTemplateName in onFormDataChange
  // In Edit mode, use extractedTemplateName from template data; in Create mode, use templateName prop
  const { onFormDataChange: onFormDataChangeProp } = props;

  // Create onFormDataChange callback that updates extractedTemplateName in Edit mode
  // This matches the Email component's onFormDataChange which updates its state
  const handleFormDataChange = useCallback((updatedFormData) => {
    const newTemplateName = updatedFormData?.['template-name'] || '';

    // In Edit mode, update extractedTemplateName state (similar to Email component updating its formData state)
    if (isEditMode && newTemplateName !== extractedTemplateName) {
      setExtractedTemplateName(newTemplateName);
    }

    // Call the parent's onFormDataChange if provided
    if (onFormDataChangeProp) {
      onFormDataChangeProp(updatedFormData);
    }

    // Call showTemplateName again with updated formData (same pattern as Email component)
    if (showTemplateName && isFullMode) {
      showTemplateName({ formData: updatedFormData, onFormDataChange: handleFormDataChange });
    }
  }, [isEditMode, extractedTemplateName, onFormDataChangeProp, showTemplateName, isFullMode]);

  useEffect(() => {
    if (showTemplateName && isFullMode) {
      // In Edit mode, use extractedTemplateName; in Create mode, use templateName prop
      const nameToUse = isEditMode ? extractedTemplateName : templateName;
      const formData = {
        'template-name': nameToUse || '',
      };
      // Pass handleFormDataChange callback so CreativesContainer can update template name
      // This is the same pattern used in Email component
      showTemplateName({ formData, onFormDataChange: handleFormDataChange });
    }
  }, [showTemplateName, isFullMode, templateName, extractedTemplateName, isEditMode, handleFormDataChange]);

  return (
    <CapSpin spinning={isLoading} tip={spinTip}>
      <CapRow>
        <CapColumn span={24}>
          {/* Subject Field */}
          <CapColumn span={24} style={{ marginBottom: CAP_SPACE_16 }}>
            <CapTagListWithInput
              inputId="template-subject"
              inputValue={subject}
              inputOnChange={handleSubjectChange}
              inputPlaceholder={formatMessage(messages.enterEmailSubject)}
              inputRequired
              inputErrorMessage={subjectError}
              headingText={formatMessage(messages.subject)}
              headingType="h4"
              headingStyle={{ marginRight: '85%' }}
              onTagSelect={handleSubjectTagSelect}
              onContextChange={handleOnTagsContextChange}
              location={location}
              tags={tags}
              injectedTags={injectedTags || {}}
              selectedOfferDetails={selectedOfferDetails}
              eventContextTags={eventContextTags}
              waitEventContextTags={waitEventContextTags}
              showHeading
              showTagList
              showInput
              containerStyle={{
                display: 'flex',
                flexDirection: 'column',
              }}
              popoverPlacement="bottomRight"
            />
          </CapColumn>

          <HTMLEditor
            ref={htmlEditorRef}
            variant="email"
            initialContent={loadedHtmlContent || ''}
            onContentChange={handleContentChange}
            onSave={handleSave}
            readOnly={isReadOnly}
            showFullscreenButton
            autoSave={false}
            tags={tags}
            injectedTags={injectedTags}
            location={location}
            eventContextTags={eventContextTags}
            waitEventContextTags={waitEventContextTags}
            selectedOfferDetails={selectedOfferDetails}
            channel={EMAIL}
            userLocale={intl.locale || 'en'}
            moduleFilterEnabled={location?.query?.type !== EMBEDDED}
            onTagContextChange={handleOnTagsContextChange}
            isFullMode={isFullMode}
            onErrorAcknowledged={handleErrorAcknowledged}
            onValidationChange={handleValidationChange}
            apiValidationErrors={mergedApiValidationErrors}
          />
        </CapColumn>
      </CapRow>
    </CapSpin>
  );
};

EmailHTMLEditor.propTypes = {
  intl: PropTypes.object.isRequired,
  location: PropTypes.object,
  params: PropTypes.object,
  getDefaultTags: PropTypes.string,
  supportedTags: PropTypes.array,
  metaEntities: PropTypes.object,
  injectedTags: PropTypes.object,
  globalActions: PropTypes.object,
  loadingTags: PropTypes.bool,
  eventContextTags: PropTypes.array,
  waitEventContextTags: PropTypes.object,
  forwardedTags: PropTypes.object,
  selectedOfferDetails: PropTypes.array,
  currentOrgDetails: PropTypes.object,
  isReadOnly: PropTypes.bool,
  fetchingLiquidTags: PropTypes.bool,
  createTemplateInProgress: PropTypes.bool,
  fetchingCmsData: PropTypes.bool,
  // Email Redux state
  Email: PropTypes.object,
  // Email actions
  emailActions: PropTypes.object,
  // Full mode props
  isFullMode: PropTypes.bool,
  templateName: PropTypes.string,
  showTemplateName: PropTypes.func,
  onFormDataChange: PropTypes.func,
  isGetFormData: PropTypes.bool,
  getFormdata: PropTypes.func,
  // Library mode props
  templateData: PropTypes.object,
  // Uploaded content from zip file
  EmailLayout: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), // eslint-disable-line react/require-default-props
  // Liquid validation
  getLiquidTags: PropTypes.func,
  showLiquidErrorInFooter: PropTypes.func,
  // Preview/Test
  // Parent loading control
  setIsLoadingContent: PropTypes.func,
  forwardedRef: PropTypes.object,
  onValidationFail: PropTypes.func,
  moduleType: PropTypes.string,
  onHtmlEditorValidationStateChange: PropTypes.func,
  isEditEmail: PropTypes.bool,
};

EmailHTMLEditor.defaultProps = {
  location: {},
  params: {},
  getDefaultTags: null,
  supportedTags: [],
  showTemplateName: null,
  metaEntities: {},
  injectedTags: {},
  globalActions: {},
  loadingTags: false,
  eventContextTags: [],
  waitEventContextTags: {},
  forwardedTags: {},
  selectedOfferDetails: [],
  currentOrgDetails: {},
  isReadOnly: false,
  fetchingLiquidTags: false,
  createTemplateInProgress: false,
  fetchingCmsData: false,
  Email: {},
  emailActions: {},
  isFullMode: false,
  templateName: '',
  onFormDataChange: null,
  isGetFormData: false,
  getFormdata: null,
  templateData: null,
  getLiquidTags: null,
  showLiquidErrorInFooter: null,
  setIsLoadingContent: null,
  forwardedRef: null,
  onValidationFail: null,
  moduleType: null,
  onHtmlEditorValidationStateChange: null,
  isEditEmail: true,
};

const EmailHTMLEditorWithIntl = injectIntl(EmailHTMLEditor);

export default forwardRef((props, ref) => <EmailHTMLEditorWithIntl {...props} forwardedRef={ref} />);
