/**
 * FocusGram Unified Feed Filter via Fetch Interception
 * Injected at DOCUMENT_START — before Instagram's JS loads.
 * 
 * This script intercepts GraphQL fetch calls and filters feed content based on:
 * - Ads (is_ad, ad_action_link, product_type, ad_id, ad_header_style)
 * - Sponsored posts (ad_action_link, ad_header_style)
 * - Suggested posts (is_suggested, is_suggested_for_you, __typename)
 * - Videos/Reels (is_video, media_type, clips_metadata)
 * - Autoplay blocking (video autoplay prevention)
 */
(function () {
  'use strict';

  // Configuration flags (set by Flutter via prefs)
  window.__fgFilterConfig = {
    blockAds: false,
    blockSponsored: false,
    blockSuggested: false,
    blockVideos: false,
    blockAutoplay: false,
    blockGraphQLQueryWhenFeedPosts: false,
  };

  const textHasAdSignal = (value) => {
    const s = String(value || '').toLowerCase();
    return (
      s === 'sponsored' ||
      s.includes('"sponsored"') ||
      s.includes('paid partnership') ||
      s.includes('promoted') ||
      s.includes('ad_id') ||
      s.includes('ad_tracking') ||
      s.includes('sponsor_tags')
    );
  };

  // Helper: Check if a node is an ad
  const isAdNode = (node) => {
    if (!node || typeof node !== 'object') return false;
    const typename = String(node.__typename || '');
    const adText = JSON.stringify({
      organic_tracking_token: node.organic_tracking_token,
      sponsor_tags: node.sponsor_tags,
      social_context: node.social_context,
      title: node.title,
      header: node.header,
      label: node.label,
      overlay_text: node.overlay_text,
    });
    
    return !!(
      node.is_ad ||
      node.is_paid_partnership ||
      node.sponsor_tags ||
      node.ad_tracking_token ||
      node.ad_action_link ||
      node.ad_id ||
      node.ad_impression_token ||
      node.ad_metadata ||
      node.commerciality_status === 'commercial' ||
      (node.product_type && node.product_type === 'ad') ||
      (node.ad_header_style && node.ad_header_style !== 'none') ||
      typename === 'GraphAdStory' ||
      typename.includes('Ad') ||
      textHasAdSignal(adText)
    );
  };

  // Helper: Check if a node is sponsored
  const isSponsoredNode = (node) => {
    if (!node || typeof node !== 'object') return false;
    
    return !!(
      node.is_paid_partnership ||
      node.sponsor_tags ||
      (node.ad_action_link && node.ad_action_link.href) ||
      (node.ad_header_style && node.ad_header_style !== 'none') ||
      textHasAdSignal(JSON.stringify(node.social_context || node.header || node.label || ''))
    );
  };

  // Helper: Check if a node is suggested content
  const isSuggestedNode = (node) => {
    if (!node || typeof node !== 'object') return false;
    const typename = String(node.__typename || '');
    const reason = JSON.stringify({
      reason: node.suggested_reason,
      social_context: node.social_context,
      title: node.title,
      header: node.header,
      label: node.label,
    }).toLowerCase();
    
    return !!(
      node.is_suggested ||
      node.is_suggested_for_you ||
      node.is_recommendation ||
      node.suggested_users ||
      node.suggested_media ||
      node.suggested_content ||
      node.recommendation_source ||
      typename.includes('Suggested') ||
      typename.includes('Recommendation') ||
      reason.includes('suggested') ||
      reason.includes('recommend')
    );
  };

  // Helper: Check if a node is a video/reel
  const isVideoNode = (node) => {
    if (!node || typeof node !== 'object') return false;
    
    return !!(
      node.is_video ||
      (node.media_type === 2) ||
      node.clips_metadata ||
      (node.__typename && (
        node.__typename.includes('Clips') ||
        node.__typename.includes('Video')
      ))
    );
  };

  const isFeedMediaNode = (node) => {
    if (!node || typeof node !== 'object') return false;
    return !!(
      node.pk ||
      node.id ||
      node.code ||
      node.media_type ||
      node.image_versions2 ||
      node.video_versions ||
      node.carousel_media ||
      node.__typename?.includes('Media') ||
      node.__typename?.includes('Timeline')
    );
  };

  // Helper: Check for media in carousel
  const hasVideoInCarousel = (node) => {
    if (!node || typeof node !== 'object') return false;

    if (node.media_type === 8) {
      const edges = node.edge_sidecar_to_children?.edges || [];
      return edges.some(edge => isVideoNode(edge.node));
    }
    return false;
  };

  // Main filter function for feed nodes
  const shouldFilterNode = (node) => {
    const config = window.__fgFilterConfig;
    
    if (!node || typeof node !== 'object') return false;

    if (config.blockGraphQLQueryWhenFeedPosts && isFeedMediaNode(node)) {
      return true;
    }

    // Check ads
    if (config.blockAds && isAdNode(node)) {
      return true;
    }

    // Check sponsored (separate from ads)
    if (config.blockSponsored && isSponsoredNode(node) && !isAdNode(node)) {
      return true;
    }

    // Check suggested content
    if (config.blockSuggested && isSuggestedNode(node)) {
      return true;
    }

    // Check videos/reels
    if (config.blockVideos && (isVideoNode(node) || hasVideoInCarousel(node))) {
      return true;
    }

    return false;
  };

  // Recursively filter GraphQL response edges
  const filterEdges = (edges, path = []) => {
    if (!Array.isArray(edges)) return edges;
    
    return edges.filter(edge => {
      if (!edge || !edge.node) return true;
      const node = edge.node;
      
      // Keep the edge if it doesn't match any filter
      if (!shouldFilterNode(node)) return true;
      
      // Log filtered content for debugging
      if (window.__fgDebugFilter) {
        const type = node.__typename || 'Unknown';
        console.debug('[FocusGram Filter]', `Filtered ${type} at ${path.join('/')}`);
      }
      
      return false;
    });
  };

  // Recursively walk GraphQL response and filter edges
  const walkAndFilter = (obj, visited = new Set()) => {
    if (!obj || typeof obj !== 'object' || visited.has(obj)) return;
    visited.add(obj);

    // Handle arrays
    if (Array.isArray(obj)) {
      obj.forEach(item => walkAndFilter(item, visited));
      return;
    }

    // Check for edges array (common GraphQL pattern)
    if (obj.edges && Array.isArray(obj.edges)) {
      obj.edges = filterEdges(obj.edges);
    }

    // Recurse into children
    for (const key in obj) {
      if (obj.hasOwnProperty(key) && key !== '__typename') {
        const val = obj[key];
        if (val && typeof val === 'object') {
          walkAndFilter(val, visited);
        }
      }
    }
  };

  // Override fetch
  const _fetch = window.fetch.bind(window);

  window.fetch = async function (input, init) {
    const url = typeof input === 'string'
      ? input
      : input instanceof URL
      ? input.href
      : input?.url ?? '';

    // Call original fetch
    let response = await _fetch(input, init);

    // Only intercept GraphQL feed queries
    if (!url.includes('/graphql') && !url.includes('/api/v1/feed')) {
      return response;
    }

    // Clone response to read body
    const cloned = response.clone();
    
    try {
      const contentType = response.headers.get('content-type') || '';
      if (!contentType.includes('application/json')) {
        return response;
      }

      const data = await cloned.json();
      
      // Filter the response data
      walkAndFilter(data);

      // Return modified response
      return new Response(JSON.stringify(data), {
        status: response.status,
        statusText: response.statusText,
        headers: response.headers,
      });
    } catch (e) {
      // On error, return original response
      return response;
    }
  };

  // Preserve native function appearance
  Object.defineProperty(window, 'fetch', {
    value: window.fetch,
    writable: true,
    configurable: true,
  });
  window.fetch.toString = () => 'function fetch() { [native code] }';

  const _xhrOpen = XMLHttpRequest.prototype.open;
  const _xhrSend = XMLHttpRequest.prototype.send;
  XMLHttpRequest.prototype.open = function (method, url) {
    this.__fgUrl = typeof url === 'string' ? url : String(url || '');
    return _xhrOpen.apply(this, arguments);
  };
  XMLHttpRequest.prototype.send = function () {
    if (
      window.__fgFilterConfig.blockVideos &&
      this.__fgUrl &&
      (this.__fgUrl.includes('/api/v1/clips/') ||
        this.__fgUrl.includes('/api/v1/discover/'))
    ) {
      try { this.abort(); } catch (_) {}
      return;
    }
    return _xhrSend.apply(this, arguments);
  };

  // Allow Flutter to update config flags
  window.__fgSetFilterConfig = function (config) {
    if (typeof config === 'object') {
      Object.assign(window.__fgFilterConfig, config);
      if (window.__fgDebugFilter) {
        console.debug('[FocusGram Filter] Config updated:', window.__fgFilterConfig);
      }
    }
  };

  // Enable debug logging
  window.__fgDebugFilter = false;
})();
