/**
 * Enhanced Rich Text Editing - TinyMCE Integration
 *
 * This module provides enhanced TinyMCE editor functionality with automatic
 * field detection and initialization for newly added fields.
 *
 * Refactored to use modular components for better maintainability:
 * - FieldStateManager: Unified state management
 * - FieldInitializer: Field initialization with retry logic
 * - FieldDiscoveryManager: Automatic field detection
 * - EditorInitializer: TinyMCE editor initialization
 * - ToolbarConfigManager: Toolbar configuration
 * - DragHandler: ACF drag-and-drop support
 *
 * Usage:
 * - Fields are automatically detected and initialized when added to the DOM
 * - For manual initialization: window.enhancedRichTextEditing.initializeFieldById('field-id')
 * - For bulk initialization: window.enhancedRichTextEditing.initializeFieldsInContainer('.container')
 * - For cleanup: window.enhancedRichTextEditing.cleanup()
 *
 * Supported field types:
 * - Standard WordPress editor fields
 * - ACF (Advanced Custom Fields) textarea fields
 * - ACF WYSIWYG fields
 * - ACF repeater fields
 * - ACF flexible content fields
 */

import tdblocks from './plugins/tdblocks';
import tdstyles from './plugins/tdstyles';
import tdlink from './plugins/tdlink';
import tdimage from './plugins/tdimage';

import {
  FieldStateManager,
  FieldInitializer,
  FieldDiscoveryManager,
  EditorInitializer,
  ToolbarConfigManager,
  DragHandler
} from './core';

/**
 * Main integration class that orchestrates all components
 */
class TinyMCEIntegration {
  constructor() {
    this.stateManager = new FieldStateManager();
    this.toolbarConfigManager = new ToolbarConfigManager();
    this.editorInitializer = new EditorInitializer(this.stateManager);
    this.fieldInitializer = new FieldInitializer(
      this.stateManager,
      this.editorInitializer,
      this.toolbarConfigManager
    );
    this.discoveryManager = new FieldDiscoveryManager(this.stateManager, this.fieldInitializer);
    this.dragHandler = new DragHandler(this.stateManager, this.fieldInitializer);
  }

  /**
   * Check if the document is ready
   * @returns {boolean}
   */
  isReady() {
    const readyState = document.readyState;
    return readyState === 'complete' || readyState === 'interactive';
  }

  /**
   * Build tinyMCEPreInit from DOM when PHP didn't output it.
   * Scans for WordPress editor containers and uses the default config.
   * @returns {Object|null}
   */
  buildPreInitFromDOM() {
    const mceInit = {};
    const defaultConfig = {
      license_key: 'gpl',
      theme: 'silver',
      skin: 'oxide',
      branding: false,
      contextmenu: false,
      highlight_on_focus: true,
      image_caption: true,
      link_default_target: '_blank',
      paste_as_text: false,
      promotion: false,
      toolbar: 'tdblocks tdstyles | tdimage table | alignleft aligncenter alignright alignjustify | bullist numlist | outdent indent | code charmap removeformat | visualblocks visualchars preview fullscreen | undo redo',
      toolbar_sticky: true,
      toolbar_sticky_offset: 32,
      plugins: 'autoresize advlist autolink charmap code link lists fullscreen preview quickbars table visualblocks visualchars wordcount tdblocks tdimage tdlink tdstyles',
      quickbars_insert_toolbar: '',
      quickbars_selection_toolbar: 'bold italic underline strikethrough | tdlink unlink | superscript subscript | forecolor backcolor',
      menubar: false,
      content_style: 'body { margin: 1rem; }',
      min_height: 500,
      newline_behavior: 'default',
      // Load the provider's editor stylesheet (e.g. TheDock's editor.css) and
      // apply the body class its scoped rules expect, so styles picked from the
      // dropdown actually render inside the editor. Absent without a provider.
      content_css: (typeof window !== 'undefined' && window.erteContentCss) || undefined,
      body_class: (typeof window !== 'undefined' && window.erteBodyClass) || undefined,
    };

    document.querySelectorAll('.wp-editor-container').forEach(container => {
      const textarea = container.querySelector('textarea.wp-editor-area');
      if (!textarea || !textarea.id) return;
      mceInit[textarea.id] = { ...defaultConfig };
    });

    const excerpt = document.getElementById('excerpt');
    if (excerpt) {
      mceInit.excerpt = { ...defaultConfig };
    }

    return Object.keys(mceInit).length > 0
      ? { baseURL: window.tinymce?.baseURL, suffix: '.min', dragDropUpload: true, mceInit, qtInit: false }
      : null;
  }

  /**
   * Initialize the TinyMCE integration
   * @param {Object} tinymce - TinyMCE instance
   * @param {Object} $ - jQuery instance
   */
  init(tinymce, $) {
    // Set up global TinyMCE references
    tinymce.$ = $;
    tinymce.editors = [];
    window.wpActiveEditor = 'content';

    // Wrap tinymce.init to intercept third-party plugins (JetEngine, etc.)
    // that call it with TinyMCE 4.x settings against our TinyMCE 7 instance
    this.wrapTinyMCEInit(tinymce);

    // Ensure tinyMCEPreInit has valid mceInit entries.
    // WordPress core may set tinyMCEPreInit with an empty mceInit {},
    // so check for actual keys, not just truthiness.
    const hasValidPreInit = window.tinyMCEPreInit
      && window.tinyMCEPreInit.mceInit
      && Object.keys(window.tinyMCEPreInit.mceInit).length > 0;

    if (!hasValidPreInit) {
      const domPreInit = this.buildPreInitFromDOM();
      if (domPreInit) {
        window.tinyMCEPreInit = domPreInit;
      }
    }

    // Always correct baseURL to point to our TinyMCE 7 vendor directory
    if (window.tinyMCEPreInit) {
      const vendorBase = tinymce.baseURL;
      window.tinyMCEPreInit.baseURL = vendorBase;
    }

    if (!window.tinyMCEPreInit || !window.tinyMCEPreInit.mceInit || Object.keys(window.tinyMCEPreInit.mceInit).length === 0) {
      console.warn('TinyMCE initialization data is missing or invalid');
      return;
    }

    // Protect tinyMCEPreInit from being overwritten by late-running WP core scripts
    // (e.g. _WP_Editors::print_default_editor_scripts outputs tinyMCEPreInit with empty mceInit)
    const protectedPreInit = window.tinyMCEPreInit;
    Object.defineProperty(window, 'tinyMCEPreInit', {
      get() { return protectedPreInit; },
      set() { /* block overwrites */ },
      configurable: true
    });

    // Register custom plugins
    this.registerPlugins(tinymce);

    // Initialize based on browser support
    if (typeof tinymce !== 'undefined') {
      if (tinymce.Env.ie && tinymce.Env.ie < 11) {
        tinymce.$('.wp-editor-wrap').removeClass('tmce-active').addClass('html-active');
      } else {
        if (this.isReady()) {
          this.initializeEditors();
        } else {
          document.addEventListener('readystatechange', () => this.initializeEditors());
        }
      }
    }

    // Handle form submission
    this.setupFormHandler();

    // Expose global API
    this.exposeGlobalAPI();
  }

  /**
   * Register TinyMCE plugins
   * @param {Object} tinymce - TinyMCE instance
   */
  registerPlugins(tinymce) {
    tinymce.PluginManager.add('tdblocks', tdblocks);
    tinymce.PluginManager.add('tdstyles', tdstyles);
    tinymce.PluginManager.add('tdlink', tdlink);
    tinymce.PluginManager.add('tdimage', tdimage);
  }

  /**
   * TinyMCE 4.x plugins that don't exist in TinyMCE 7
   */
  static LEGACY_PLUGINS = new Set([
    'colorpicker', 'contextmenu', 'hr', 'paste', 'tabfocus', 'textcolor',
    'wordpress', 'wpautoresize', 'wpeditimage', 'wpemoji', 'wpgallery',
    'wplink', 'wptextpattern', 'compat3x', 'textpattern'
  ]);

  /**
   * Wrap tinymce.init to normalize TinyMCE 4.x settings from third-party plugins
   * (e.g. JetEngine, WPBakery) so they work with TinyMCE 7.
   * @param {Object} tinymce - TinyMCE instance
   */
  wrapTinyMCEInit(tinymce) {
    const originalInit = tinymce.init.bind(tinymce);
    const self = this;

    tinymce.init = function (settings) {
      if (settings && settings.theme === 'modern') {
        console.log('ERTE: Intercepted TinyMCE 4.x init call, normalizing settings for TinyMCE 7', settings.selector || settings.target);
        settings = self.normalizeLegacySettings(settings);
      }
      return originalInit(settings);
    };
  }

  /**
   * Normalize TinyMCE 4.x settings to TinyMCE 7 compatible settings
   * @param {Object} settings - Legacy TinyMCE 4.x settings
   * @returns {Object} Normalized settings for TinyMCE 7
   */
  normalizeLegacySettings(settings) {
    const preInit = window.tinyMCEPreInit;
    const baseConfig = preInit?.mceInit
      ? Object.values(preInit.mceInit)[0]
      : null;

    // Fix theme and skin
    settings.theme = 'silver';
    settings.skin = 'oxide';
    delete settings.theme_url;
    delete settings.skin_url;

    // Set baseURL to our vendor path
    settings.base_url = window.tinymce?.baseURL;

    // Strip legacy plugins and add our defaults
    if (settings.plugins) {
      const plugins = settings.plugins.split(',').map(p => p.trim())
        .filter(p => !TinyMCEIntegration.LEGACY_PLUGINS.has(p));
      // Add essential TinyMCE 7 plugins
      const essentialPlugins = ['autoresize', 'lists', 'link', 'charmap', 'fullscreen', 'code', 'table',
        'quickbars', 'advlist', 'autolink', 'visualblocks', 'visualchars', 'wordcount',
        'tdblocks', 'tdstyles', 'tdlink', 'tdimage'];
      const pluginSet = new Set([...plugins, ...essentialPlugins]);
      settings.plugins = Array.from(pluginSet).join(' ');
    }

    // Replace TinyMCE 4 toolbar1/toolbar2 with a single toolbar for TinyMCE 7
    const defaultToolbar = 'tdblocks tdstyles | tdimage table | alignleft aligncenter alignright alignjustify | bullist numlist | outdent indent | code charmap removeformat | visualblocks visualchars preview fullscreen | undo redo';
    settings.toolbar = baseConfig?.toolbar || defaultToolbar;
    delete settings.toolbar1;
    delete settings.toolbar2;
    delete settings.toolbar3;
    delete settings.toolbar4;

    // Set quickbars
    const defaultQuickbars = 'bold italic underline strikethrough | tdlink unlink | superscript subscript | forecolor backcolor';
    settings.quickbars_selection_toolbar = baseConfig?.quickbars_selection_toolbar || defaultQuickbars;
    settings.quickbars_insert_toolbar = baseConfig?.quickbars_insert_toolbar || '';

    // Apply other TinyMCE 7 defaults
    settings.license_key = 'gpl';
    settings.branding = false;
    settings.promotion = false;
    settings.menubar = settings.menubar !== undefined ? settings.menubar : false;

    // Replace WP's legacy content_css (wp-content.css) with TinyMCE 7 default
    settings.content_css = baseConfig?.content_css || 'default';

    return settings;
  }

  /**
   * Initialize all editors
   */
  initializeEditors() {
    if (!this.isReady()) return;

    const mceInit = window.tinyMCEPreInit.mceInit;

    Object.entries(mceInit).forEach(([id, config]) => {
      // Skip if already initialized
      if (this.stateManager.isInitialized(id)) return;

      // Skip quicktags-only editors
      if (window.tinyMCEPreInit.qtInit?.hasOwnProperty(id)) return;

      const $wrap = jQuery(`#wp-${id}-wrap`);
      const inPostbox = $wrap.parents('.postbox').length > 0;

      // Wait for complete readiness for postbox editors
      if (!this.isReady() || (inPostbox && document.readyState !== 'complete')) return;

      // Mark as initialized to prevent duplicates
      this.stateManager.markAsInitialized(id);

      const baseConfig = this.editorInitializer.getBaseConfig(id, config);

      if (id === 'acf_content') {
        this.handleACFFields(baseConfig);
      } else if (id === 'excerpt') {
        baseConfig.min_height = 150;
        this.editorInitializer.initEditor(`#${id}`, baseConfig, true);
      } else if (id === 'content') {
        this.handleStandardEditor(id, baseConfig);
      } else {
        this.editorInitializer.initEditor(`#${id}`, baseConfig);
      }

      if (!window.wpActiveEditor) {
        window.wpActiveEditor = id;
      }
    });

    // Start field discovery for dynamic fields
    this.handleHiddenFields();
    this.discoveryManager.start();
    this.dragHandler.setup();
  }

  /**
   * Handle standard WordPress editor field
   * @param {string} id - Editor ID
   * @param {Object} baseConfig - Base configuration
   */
  handleStandardEditor(id, baseConfig) {
    const $wrap = jQuery(`#wp-${id}-wrap`);
    const $editorContainer = $wrap.find(`#wp-${id}-editor-container`);
    const toolbar = $editorContainer.data('toolbar');

    let editorConfig = { ...baseConfig, selector: `#${id}` };

    if (toolbar) {
      editorConfig = this.toolbarConfigManager.configureFromToolbar(editorConfig, toolbar);
    }

    this.editorInitializer.initEditor(`#${id}`, editorConfig);
  }

  /**
   * Handle ACF field editors
   * @param {Object} baseConfig - Base configuration
   */
  handleACFFields(baseConfig) {
    jQuery('.acf-fields .acf-input textarea').each((_, textarea) => {
      const $textarea = jQuery(textarea);
      const id = $textarea.attr('id');

      if ($textarea.is(':hidden')) {
        // Track hidden fields for later
        return;
      }

      const $field = $textarea.closest('.acf-field');
      const toolbar = this.toolbarConfigManager.getToolbarFromField($field);

      let editorConfig = { ...baseConfig, selector: `#${id}` };

      if (toolbar) {
        editorConfig = this.toolbarConfigManager.configureFromToolbar(editorConfig, toolbar);
      }

      const isWysiwyg = $textarea.hasClass('acf-wysiwyg');
      this.editorInitializer.initEditor(`#${id}`, editorConfig, !isWysiwyg);
    });
  }

  /**
   * Handle hidden ACF fields (in repeaters, etc.)
   */
  handleHiddenFields() {
    // Hidden fields will be handled by the discovery manager when they become visible
    // This is a placeholder for any specific hidden field handling logic
  }

  /**
   * Set up form submission handler
   */
  setupFormHandler() {
    const postForm = document.getElementById('post');
    if (postForm) {
      postForm.addEventListener('formdata', e => {
        const formData = e.formData;
        formData.forEach((value, key) => {
          if (this.stateManager.isInline(key)) {
            formData.set(key, value.replace(/^<p>(.*)<\/p>$/s, '$1'));
          }
        });
      });
    }
  }

  /**
   * Expose global API for external use
   */
  exposeGlobalAPI() {
    window.enhancedRichTextEditing = {
      // Field initialization
      initializeFieldById: (id, force = false) => {
        const textarea = document.getElementById(id);
        if (textarea) {
          if (force) {
            this.fieldInitializer.forceInitialize(id, textarea);
          } else {
            this.fieldInitializer.initializeField(id, textarea);
          }
        } else {
          console.warn(`Textarea with ID ${id} not found in DOM`);
        }
      },

      forceInitializeField: (id, textarea) => {
        textarea = textarea || document.getElementById(id);
        if (textarea) {
          this.fieldInitializer.forceInitialize(id, textarea);
        }
      },

      initializeFieldsInContainer: container => {
        this.discoveryManager.initializeFieldsInContainer(container);
      },

      // Scanning and discovery
      scanForNewFields: () => {
        this.discoveryManager.scanForFields();
      },

      forceFieldDiscovery: () => {
        this.discoveryManager.forceScan();
      },

      retryPendingFields: () => {
        this.fieldInitializer.retryFailedFields();
      },

      // Diagnostics
      diagnoseTinyMCEStatus: id => {
        if (id) {
          return this.stateManager.diagnose(id);
        }

        // Diagnose all
        const results = {
          timestamp: new Date().toISOString(),
          tinymceGlobal: !!window.tinymce,
          tinymceVersion: window.tinymce?.majorVersion,
          summary: this.stateManager.getStatusSummary(),
          editors: []
        };

        this.stateManager.getInitializedFields().forEach(fieldId => {
          results.editors.push(this.stateManager.diagnose(fieldId));
        });

        return results;
      },

      getInitializationStatus: () => {
        return this.stateManager.getInitializationStatus();
      },

      // Cleanup
      cleanup: () => {
        this.discoveryManager.stop();
        this.dragHandler.cleanup();
        this.fieldInitializer.cleanup();
        this.stateManager.cleanup();
      },

      // Expose state for debugging
      state: this.stateManager
    };
  }
}

// Create the main initialization function
const initMce = function (tinymce, $) {
  const integration = new TinyMCEIntegration();
  integration.init(tinymce, $);
};

// Export the initialization wrapper
export default function (tinymce, $) {
  return function () {
    return initMce(tinymce, $);
  };
}
