/**
 * FieldStateManager - Unified state management for editor fields
 *
 * Replaces the previous 8 overlapping state structures with a single
 * state machine that has clear transitions.
 *
 * State transitions:
 * DISCOVERED → PROCESSING → INITIALIZED
 *                   ↓
 *                FAILED → (can retry → PROCESSING)
 */

export const FIELD_STATES = {
  DISCOVERED: 'discovered',
  PROCESSING: 'processing',
  INITIALIZED: 'initialized',
  FAILED: 'failed'
};

export class FieldStateManager {
  constructor() {
    // Single source of truth for field states
    this.fields = new Map();
    this.observers = [];
    this.dragState = {
      isDragging: false,
      destroyedEditors: new Map()
    };
    this.inlineEditors = new Set();
  }

  /**
   * Get current state of a field
   * @param {string} id - Field ID
   * @returns {string|null} Current state or null if not tracked
   */
  getState(id) {
    return this.fields.get(id)?.state || null;
  }

  /**
   * Get field data
   * @param {string} id - Field ID
   * @returns {Object|null} Field data or null
   */
  getFieldData(id) {
    return this.fields.get(id) || null;
  }

  /**
   * Set field state with automatic cleanup of previous state data
   * @param {string} id - Field ID
   * @param {string} newState - New state from FIELD_STATES
   * @param {Object} data - Additional state data
   */
  setState(id, newState, data = {}) {
    const currentData = this.fields.get(id) || {};

    // Clear any existing retry timer
    if (currentData.retryTimer) {
      clearTimeout(currentData.retryTimer);
    }

    this.fields.set(id, {
      ...currentData,
      state: newState,
      ...data,
      lastUpdated: Date.now()
    });
  }

  // State check methods
  isDiscovered(id) {
    return this.getState(id) === FIELD_STATES.DISCOVERED;
  }

  isProcessing(id) {
    return this.getState(id) === FIELD_STATES.PROCESSING;
  }

  isInitialized(id) {
    return this.getState(id) === FIELD_STATES.INITIALIZED;
  }

  isFailed(id) {
    return this.getState(id) === FIELD_STATES.FAILED;
  }

  /**
   * Check if field is being tracked at all
   * @param {string} id - Field ID
   * @returns {boolean}
   */
  isTracked(id) {
    return this.fields.has(id);
  }

  // State transition methods
  markAsDiscovered(id, textarea) {
    this.setState(id, FIELD_STATES.DISCOVERED, { textarea });
  }

  markAsProcessing(id) {
    this.setState(id, FIELD_STATES.PROCESSING);
  }

  markAsInitialized(id) {
    this.setState(id, FIELD_STATES.INITIALIZED);
  }

  markAsFailed(id, error = null, retryCount = 0) {
    this.setState(id, FIELD_STATES.FAILED, { error, retryCount });
  }

  /**
   * Mark field as inline editor
   * @param {string} id - Field ID
   */
  markAsInline(id) {
    this.inlineEditors.add(id);
  }

  /**
   * Check if field is an inline editor
   * @param {string} id - Field ID
   * @returns {boolean}
   */
  isInline(id) {
    return this.inlineEditors.has(id);
  }

  /**
   * Centralized field exclusion logic
   * @param {string} id - Field ID
   * @param {Element} textarea - Textarea element
   * @returns {boolean} True if field should be excluded from initialization
   */
  shouldExclude(id, textarea) {
    if (!textarea || !id) {
      return true;
    }

    // If already initialized, check if editor actually exists
    if (this.isInitialized(id)) {
      const editor = window.tinymce?.get(id);
      if (editor) {
        return true; // Already has a working editor
      }
      // Editor missing, allow re-initialization
      this.removeField(id);
      return false;
    }

    // Skip if currently being processed
    if (this.isProcessing(id)) {
      return true;
    }

    // Check for ACF clone templates
    const isCloneTemplate =
      textarea.closest('.clones') !== null ||
      textarea.closest('[data-id="acfcloneindex"]') !== null ||
      id.includes('acfcloneindex');

    // Check for jQuery UI sortable helpers
    const isSortableHelper =
      textarea.closest('.ui-sortable-helper') !== null ||
      textarea.closest('.ui-sortable-placeholder') !== null;

    return isCloneTemplate || isSortableHelper;
  }

  /**
   * Get all fields in a specific state
   * @param {string} state - State to filter by
   * @returns {Array<string>} Array of field IDs
   */
  getFieldsByState(state) {
    return Array.from(this.fields.entries())
      .filter(([, data]) => data.state === state)
      .map(([id]) => id);
  }

  /**
   * Get all initialized field IDs
   * @returns {Array<string>}
   */
  getInitializedFields() {
    return this.getFieldsByState(FIELD_STATES.INITIALIZED);
  }

  /**
   * Get all failed fields that can be retried
   * @param {number} maxRetries - Maximum retry count to consider
   * @returns {Array<{id: string, retryCount: number}>}
   */
  getRetryableFields(maxRetries = 3) {
    return Array.from(this.fields.entries())
      .filter(([, data]) => data.state === FIELD_STATES.FAILED && (data.retryCount || 0) < maxRetries)
      .map(([id, data]) => ({ id, retryCount: data.retryCount || 0 }));
  }

  /**
   * Clean up field data
   * @param {string} id - Field ID to remove
   */
  removeField(id) {
    const fieldData = this.fields.get(id);
    if (fieldData?.retryTimer) {
      clearTimeout(fieldData.retryTimer);
    }
    this.fields.delete(id);
    this.inlineEditors.delete(id);
  }

  /**
   * Store retry timer for a field
   * @param {string} id - Field ID
   * @param {number} timer - Timer ID
   */
  setRetryTimer(id, timer) {
    const fieldData = this.fields.get(id);
    if (fieldData) {
      fieldData.retryTimer = timer;
    }
  }

  /**
   * Add an observer for cleanup tracking
   * @param {MutationObserver|Object} observer - Observer to track
   */
  addObserver(observer) {
    this.observers.push(observer);
  }

  /**
   * Get status summary for diagnostics
   * @returns {Object} Status summary
   */
  getStatusSummary() {
    const summary = {
      total: this.fields.size,
      inline: this.inlineEditors.size
    };

    Object.values(FIELD_STATES).forEach(state => {
      summary[state] = this.getFieldsByState(state).length;
    });

    return summary;
  }

  /**
   * Get detailed diagnostics for a specific field
   * @param {string} id - Field ID
   * @returns {Object} Diagnostic information
   */
  diagnose(id) {
    const fieldData = this.fields.get(id);
    const textarea = document.getElementById(id);
    const editor = window.tinymce?.get(id);

    return {
      id,
      tracked: this.isTracked(id),
      state: this.getState(id),
      fieldData: fieldData ? { ...fieldData, retryTimer: !!fieldData.retryTimer } : null,
      textareaExists: !!textarea,
      textareaVisible: textarea ? textarea.offsetParent !== null : false,
      editorExists: !!editor,
      editorReady: editor?.initialized || false,
      isInline: this.isInline(id)
    };
  }

  /**
   * Complete cleanup of all state
   */
  cleanup() {
    // Clear all timers
    this.fields.forEach((data) => {
      if (data.retryTimer) {
        clearTimeout(data.retryTimer);
      }
    });

    // Disconnect observers
    this.observers.forEach(observer => {
      if (observer && typeof observer.disconnect === 'function') {
        observer.disconnect();
      }
    });

    // Clear all state
    this.fields.clear();
    this.observers = [];
    this.inlineEditors.clear();
    this.dragState = {
      isDragging: false,
      destroyedEditors: new Map()
    };
  }

  /**
   * Get initialization status for external API
   * @returns {Object}
   */
  getInitializationStatus() {
    return {
      initialized: this.getFieldsByState(FIELD_STATES.INITIALIZED),
      processing: this.getFieldsByState(FIELD_STATES.PROCESSING),
      discovered: this.getFieldsByState(FIELD_STATES.DISCOVERED),
      failed: this.getFieldsByState(FIELD_STATES.FAILED)
    };
  }
}

export default FieldStateManager;
