/* global wp, fetch, ajaxurl */

export function registerMediaUpload(Alpine) {
  Alpine.data('mediaUpload', (config) => ({
    // Config
    ref: config.ref || 'mediaUpload',
    xModelId: config.xModelId || '',
    xModelUrl: config.xModelUrl || '',
    xModelSize: config.xModelSize || '',
    initialAttachmentId: config.initialAttachmentId || 0,
    initialPreviewUrl: config.initialPreviewUrl || '',
    initialSize: config.initialSize || 'medium',
    sizes: config.sizes || { thumbnail: 'Thumbnail', medium: 'Medium', large: 'Large', full: 'Full' },
    selectTitle: config.selectTitle || 'Select Image',
    selectButton: config.selectButton || 'Use This Image',
    onChangeExpr: config.onChangeExpr || '',

    // Local reactive state
    attachmentId: 0,
    previewUrl: '',
    size: 'medium',

    init() {
      // Initialize from either x-model (parent context) or initial values (PHP)
      this.$nextTick(() => {
        this.syncFromParent();
      });

      // Watch parent context changes (e.g., when currentEmail is loaded via AJAX)
      if (this.xModelId) {
        this.$watch(() => this.tryEval(this.xModelId), () => this.syncFromParent());
      }
      if (this.xModelUrl) {
        this.$watch(() => this.tryEval(this.xModelUrl), () => this.syncFromParent());
      }
      if (this.xModelSize) {
        this.$watch(() => this.tryEval(this.xModelSize), () => this.syncFromParent());
      }

      // Keep parent in sync when local changes (only if x-model is provided)
      if (this.xModelId) {
        this.$watch('attachmentId', (value) => {
          this.syncParent(this.xModelId, value);
          this.triggerOnChange();
        });
      }

      if (this.xModelUrl) {
        this.$watch('previewUrl', (value) => {
          this.syncParent(this.xModelUrl, value);
        });
      }

      if (this.xModelSize) {
        this.$watch('size', (value) => {
          this.syncParent(this.xModelSize, value);
        });
      }

      // Additional watcher to force image update when previewUrl changes locally
      this.$watch('previewUrl', () => {
        this.forceImageUpdate();
      });
    },

        syncFromParent() {
      // Try to get values from parent Alpine context first
      let attachmentId = this.tryEval(this.xModelId);
      let previewUrl = this.tryEval(this.xModelUrl);
      let size = this.tryEval(this.xModelSize);

      // Fallback to initial values from PHP if parent context is not available
      if (attachmentId === null) {
        attachmentId = this.initialAttachmentId;
      }
   
      if (previewUrl === null) {
        previewUrl = this.initialPreviewUrl;
      }
      
      if (size === null) {
        size = this.initialSize;
      }

      // Only update if values actually changed to avoid infinite loops
      const newAttachmentId = parseInt(attachmentId || 0);
      const newPreviewUrl = previewUrl || '';
      const newSize = size || 'medium';

      if (this.attachmentId !== newAttachmentId) {
        this.attachmentId = newAttachmentId;
      }
      if (this.previewUrl !== newPreviewUrl) {
        this.previewUrl = newPreviewUrl;
        this.forceImageUpdate();
      }
      if (this.size !== newSize) {
        this.size = newSize;
      }
 

    },

    // Force update image src attribute directly as fallback for x-bind:src issues
    forceImageUpdate() {
      this.$nextTick(() => {
        const imgElement = this.$el.querySelector('img');
        if (imgElement && this.previewUrl) {
          imgElement.src = this.previewUrl;
        }
      });
    },

    tryEval(expr) {
      if (!expr) return null;
      const root = this.$refs[this.ref] || this.$root;
      try {
        const varName = (expr && expr.indexOf('.') !== -1) ? expr.split('.')[0] : expr;
        const safeExpr = varName !== expr
          ? `(typeof ${varName} !== 'undefined' && ${varName} ? ${expr} : null)`
          : `(typeof ${varName} !== 'undefined' ? ${expr} : null)`;
        return Alpine.evaluate(root, safeExpr);
      } catch (e) {
        return null;
      }
    },

    // Called from x-effect to safely digest parent's state when available
    digestParent(exprId, exprUrl, exprSize) {
      const id = this.tryEval(exprId);
      const url = this.tryEval(exprUrl);
      const size = this.tryEval(exprSize);

      if (id !== null) this.attachmentId = parseInt(id || 0);
      if (url !== null) {
        this.previewUrl = url || '';
        this.forceImageUpdate();
      }
      if (size !== null) this.size = size || 'medium';
    },

    syncParent(expr, value) {
      if (!expr) return;
      const root = this.$refs[this.ref] || this.$root;
      try {
        const varName = (expr && expr.indexOf('.') !== -1) ? expr.split('.')[0] : expr;
        const hasParent = Alpine.evaluate(root, `(typeof ${varName} !== 'undefined' && ${varName} !== null)`);
        if (!hasParent) return; // parent object is not available (e.g., currentEmail is null)

        Alpine.evaluate(root, `${expr} = ${JSON.stringify(value)}`);
        // Track explicit removal state in currentEmail for saves
        if (expr.indexOf('currentEmail.banner_attachment_id') === 0) {
          Alpine.evaluate(root, `(typeof currentEmail !== 'undefined' && currentEmail ? (currentEmail.banner_removed = ${value ? 'false' : 'true'}) : null)`);
        }
      } catch (e) {}
    },

    triggerOnChange() {
      if (!this.onChangeExpr) return;
      const root = this.$refs[this.ref] || this.$root;
      try {
        // If parent provided refreshPreview(), append preview params to iframe src
        if (this.onChangeExpr === 'refreshPreview()') {
          const iframe = document.getElementById('email-preview-frame-inline');
          if (iframe) {
            // Build url from base preview endpoint to avoid stale params stacking
            const base = iframe.getAttribute('data-preview-base') || iframe.src;
            const url = new URL(base, window.location.origin);
            if (this.attachmentId) {
              url.searchParams.set('preview_banner_id', String(this.attachmentId));
              if (typeof this.size === 'string' && this.size !== 'custom') {
                url.searchParams.set('preview_banner_size', String(this.size));
              } else {
                url.searchParams.delete('preview_banner_size');
              }
            } else {
              // Explicitly signal removal for preview
              url.searchParams.set('preview_banner_id', '0');
              url.searchParams.delete('preview_banner_size');
            }
            // cache-bust
            url.searchParams.set('t', String(Date.now()));
            iframe.src = url.toString();
          }
        } else {
          Alpine.evaluate(root, this.onChangeExpr);
        }
      } catch (e) {}
    },

    hasImage() {
      return !!this.attachmentId && !!this.previewUrl;
    },

    openMediaUploader() {
      if (typeof wp === 'undefined' || !wp.media) {
        alert('WordPress media library is not available.');
        return;
      }

      const frame = wp.media({
        title: this.selectTitle,
        button: { text: this.selectButton },
        multiple: false,
        library: { type: 'image' }
      });

      frame.on('select', () => {
        const attachment = frame.state().get('selection').first().toJSON();
        this.attachmentId = attachment.id;
        
        // Handle both named sizes (string) and custom dimensions (array)
        if (typeof this.size === 'string' && attachment.sizes && attachment.sizes[this.size]) {
          this.previewUrl = attachment.sizes[this.size].url;
        } else {
          // For custom dimensions (array) or when named size is not available, use full size
          this.previewUrl = attachment.url;
        }
        
        this.forceImageUpdate();
      });

      frame.open();
    },

    removeImage() {
      this.attachmentId = 0;
      this.previewUrl = '';
    },

    handleSizeChange(newSize) {
      this.size = newSize;
      if (!this.attachmentId) return;

      // For custom dimensions, don't try to fetch new sizes - use current URL
      if (newSize === 'custom' || Array.isArray(newSize)) {
        this.triggerOnChange();
        return;
      }

      // Use WordPress media API to get the new size URL if available
      if (typeof wp !== 'undefined' && wp.media && wp.media.attachment) {
        const attachment = wp.media.attachment(this.attachmentId);
        attachment.fetch().then(() => {
          const sizes = attachment.get('sizes');
          let newUrl = attachment.get('url'); // fallback to full size
          
          if (sizes && sizes[newSize] && sizes[newSize].url) {
            newUrl = sizes[newSize].url;
          }
          
          this.previewUrl = newUrl;
          this.forceImageUpdate();
          this.triggerOnChange();
        });
        return;
      }

      // Fallback: try AJAX if WordPress media API is not available
      this.fetchAttachmentUrl(newSize);
    },

    fetchAttachmentUrl(size) {
      // For custom dimensions, don't try to fetch - just trigger change
      if (size === 'custom' || Array.isArray(size)) {
        this.triggerOnChange();
        return;
      }

      // Get nonce and ajaxurl from multiple possible sources
      const nonce = (window.rewardswpEmailsData && window.rewardswpEmailsData.nonce) || 
                   (window.rewardswp && window.rewardswp.nonce) ||
                   '';
      const ajaxUrl = ajaxurl || 
                     (window.rewardswpEmailsData && window.rewardswpEmailsData.ajaxurl) ||
                     (window.rewardswp && window.rewardswp.ajaxurl) ||
                     '';

      if (!nonce || !ajaxUrl) {
        console.warn('MediaUpload: Missing nonce or ajaxurl for fetchAttachmentUrl');
        return;
      }

      // Fetch new URL for the selected size
      const form = new URLSearchParams();
      form.append('action', 'rewardswp_get_attachment_url');
      form.append('_ajax_nonce', nonce);
      form.append('attachment_id', this.attachmentId);
      form.append('size', size);

      fetch(ajaxUrl, {
        method: 'POST',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        body: form
      })
        .then((r) => r.json())
        .then((data) => {
          if (data && data.success && data.data && data.data.url) {
            this.previewUrl = data.data.url;
            this.forceImageUpdate();
            this.triggerOnChange();
          }
        })
        .catch(() => {});
    }
  }));
}


