import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'session_manager.dart';
import 'settings_service.dart';
import 'injection_controller.dart';
import '../scripts/grayscale.dart' as grayscale;
import '../scripts/ui_hider.dart' as ui_hider;
import '../scripts/content_disabling.dart' as content_disabling;
import '../scripts/video_downloader.dart' as video_downloader;

// Core JS and CSS payloads injected into the Instagram WebView.
//
// WARNING: Do not add any network interception logic ("ghost mode") here.
// All scripts in this file must be limited to UI behaviour, navigation helpers,
// and local-only features that do not modify data sent to Meta's servers.

// ── CSS payloads ──────────────────────────────────────────────────────────────

/// Base UI polish — hides scrollbars and Instagram's nav tab-bar.
const String kGlobalUIFixesCSS = '''
  ::-webkit-scrollbar { display: none !important; width: 0 !important; height: 0 !important; }
  * {
    -ms-overflow-style: none !important;
    scrollbar-width: none !important;
    -webkit-tap-highlight-color: transparent !important;
  }
  body > div > div > [role="tablist"]:not([role="dialog"] [role="tablist"]),
  [aria-label="Direct"] header {
     display: none !important;
     visibility: hidden !important;
     height: 0 !important;
     pointer-events: none !important;
  }
''';

/// Blurs images/videos in the home feed AND on Explore.
const String kBlurHomeFeedAndExploreCSS = '''
  body[path="/"] article img,
  body[path="/"] article video,
  body[path^="/explore"] img,
  body[path^="/explore"] video,
  body[path="/explore/"] img,
  body[path="/explore/"] video {
    filter: blur(20px) !important;
    transition: filter 0.15s ease !important;
  }
  body[path="/"] article img:hover,
  body[path="/"] article video:hover,
  body[path^="/explore"] img:hover,
  body[path^="/explore"] video:hover {
    filter: blur(20px) !important;
  }
''';

/// Prevents text selection to keep the app feeling native (only when disabled).
const String kDisableSelectionCSS = '''
  * { -webkit-user-select: none !important; user-select: none !important; }
''';

/// Hides reel posts in the home feed when no Reel Session is active.
const String kHideReelsFeedContentCSS = '''
  a[href*="/reel/"],
  div[data-media-type="2"] {
    display: none !important;
    visibility: hidden !important;
  }
''';

// ── JavaScript helpers ────────────────────────────────────────────────────────

const String kDismissAppBannerJS = '''
  (function fgDismissBanner() {
    ['[id*="app-banner"]','[class*="app-banner"]',
     'div[role="dialog"][aria-label*="app"]','[id*="openInApp"]']
     .forEach(s => document.querySelectorAll(s).forEach(el => el.remove()));
  })();
''';

const String kStrictReelsBlockJS = r'''
  (function fgReelsBlock() {
    if (window.__fgReelsBlockPatched) return;
    window.__fgReelsBlockPatched = true;
    document.addEventListener('click', e => {
      if (window.__focusgramSessionActive) return;
      const a = e.target && e.target.closest('a[href*="/reels/"]');
      if (!a) return;
      e.preventDefault();
      e.stopPropagation();
      window.location.href = '/reels/?fg=blocked';
    }, true);
  })();
''';

const String kTrackPathJS = '''
  (function fgTrackPath() {
    if (window.__fgPathTrackerRunning) return;
    window.__fgPathTrackerRunning = true;
    let last = window.location.pathname;
    function check() {
      const p = window.location.pathname;
      if (p !== last) {
        last = p;
        if (document.body) document.body.setAttribute('path', p);
        if (window.flutter_inappwebview) {
          window.flutter_inappwebview.callHandler('UrlChange', p);
        }
      }
    }
    if (document.body) document.body.setAttribute('path', last);
    setInterval(check, 500);
  })();
''';

const String kThemeDetectorJS = r'''
  (function fgThemeSync() {
    if (window.__fgThemeSyncRunning) return;
    window.__fgThemeSyncRunning = true;
    function getTheme() {
      try {
        const h = document.documentElement;
        if (h.classList.contains('style-dark')) return 'dark';
        if (h.classList.contains('style-light')) return 'light';
        const bg = window.getComputedStyle(document.body).backgroundColor;
        const rgb = bg.match(/\d+/g);
        if (rgb && rgb.length >= 3) {
          const luminance = (0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2]) / 255;
          return luminance < 0.5 ? 'dark' : 'light';
        }
      } catch(_) {}
      return 'dark';
    }
    let last = '';
    function check() {
      const current = getTheme();
      if (current !== last) {
        last = current;
        if (window.flutter_inappwebview) {
          window.flutter_inappwebview.callHandler('FocusGramThemeChannel', current);
        }
      }
    }
    setInterval(check, 1500);
    check();
  })();
''';

const String kReelsMutationObserverJS = r'''
  (function fgReelLock() {
    if (window.__fgReelLockRunning) return;
    window.__fgReelLockRunning = true;

    const MODAL_SEL = '[role="dialog"],[role="menu"],[role="listbox"],[class*="Modal"],[class*="Sheet"],[class*="Drawer"],._aano,[class*="caption"]';

    function lockMode() {
      // Only lock scroll when: DM reel playing OR disableReelsEntirely enabled
      const isDmReel = window.location.pathname.includes('/direct/') &&
                       !!document.querySelector('[class*="ReelsVideoPlayer"]');
      if (isDmReel) return 'dm_reel';
      if (window.__fgDisableReelsEntirely === true) return 'disabled';
      return null;
    }

    function isLocked() { return lockMode() !== null; }

    function allowInteractionTarget(t) {
      if (!t || !t.closest) return false;
      if (t.closest('input,textarea,[contenteditable="true"]')) return true;
      if (t.closest(MODAL_SEL)) return true;
      return false;
    }

    let sy = 0;
    document.addEventListener('touchstart', e => {
      sy = e.touches && e.touches[0] ? e.touches[0].clientY : 0;
    }, { capture: true, passive: true });

    document.addEventListener('touchmove', e => {
      if (!isLocked()) return;
      const dy = e.touches && e.touches[0] ? e.touches[0].clientY - sy : 0;
      if (Math.abs(dy) > 2) {
        if (window.location.pathname.includes('/direct/')) {
          window.__fgDmReelAlreadyLoaded = true;
        }
        if (allowInteractionTarget(e.target)) return;
        if (e.cancelable) e.preventDefault();
        e.stopPropagation();
      }
    }, { capture: true, passive: false });

    function block(e) {
      if (!isLocked()) return;
      if (allowInteractionTarget(e.target)) return;
      if (e.cancelable) e.preventDefault();
      e.stopPropagation();
    }
    document.addEventListener('wheel', block, { capture: true, passive: false });
    document.addEventListener('keydown', e => {
      if (!['ArrowDown','ArrowUp',' ','PageUp','PageDown'].includes(e.key)) return;
      if (e.target && e.target.closest && e.target.closest('input,textarea,[contenteditable="true"]')) return;
      block(e);
    }, { capture: true, passive: false });

    const REEL_SEL = '[class*="ReelsVideoPlayer"], video';
    let __fgOrigHtmlOverflow = null;
    let __fgOrigBodyOverflow = null;

    function applyOverflowLock() {
      try {
        const mode = lockMode();
        const hasReel = !!document.querySelector(REEL_SEL);
        if ((mode === 'dm_reel' || mode === 'disabled') && hasReel) {
          if (__fgOrigHtmlOverflow === null) {
            __fgOrigHtmlOverflow = document.documentElement.style.overflow || '';
            __fgOrigBodyOverflow = document.body ? (document.body.style.overflow || '') : '';
          }
          document.documentElement.style.overflow = 'hidden';
          if (document.body) document.body.style.overflow = 'hidden';
        } else if (__fgOrigHtmlOverflow !== null) {
          document.documentElement.style.overflow = __fgOrigHtmlOverflow;
          if (document.body) document.body.style.overflow = __fgOrigBodyOverflow || '';
          __fgOrigHtmlOverflow = null;
          __fgOrigBodyOverflow = null;
        }
      } catch (_) {}
    }

    function sync() {
      const reels = document.querySelectorAll(REEL_SEL);
      applyOverflowLock();
      if (window.location.pathname.includes('/direct/') && reels.length > 0) {
        if (!window.__fgDmReelTimer) {
          window.__fgDmReelTimer = setTimeout(() => {
            if (document.querySelector(REEL_SEL)) window.__fgDmReelAlreadyLoaded = true;
            window.__fgDmReelTimer = null;
          }, 3500);
        }
      }
      if (reels.length === 0) {
        if (window.__fgDmReelTimer) { clearTimeout(window.__fgDmReelTimer); window.__fgDmReelTimer = null; }
        window.__fgDmReelAlreadyLoaded = false;
      }
    }

    sync();
    new MutationObserver(ms => {
      if (ms.some(m => m.addedNodes.length || m.removedNodes.length)) sync();
    }).observe(document.body, { childList: true, subtree: true });

    if (!window.__fgIsolatedPlayerSync) {
      window.__fgIsolatedPlayerSync = true;
      let _lastPath = window.location.pathname;
      setInterval(() => {
        const p = window.location.pathname;
        if (p === _lastPath) return;
        _lastPath = p;
        window.__focusgramIsolatedPlayer = p.includes('/reel/') && !p.startsWith('/reels');
        if (!p.includes('/direct/')) window.__fgDmReelAlreadyLoaded = false;
        applyOverflowLock();
      }, 400);
    }
  })();
''';

const String kBadgeMonitorJS = r'''
  (function fgBadgeMonitor() {
    if (window.__fgBadgeMonitorRunning) return;
    window.__fgBadgeMonitorRunning = true;
    const startedAt = Date.now();
    let initialised = false;
    let lastDmCount = 0, lastNotifCount = 0, lastTitleUnread = 0;

    function parseBadgeCount(el) {
      if (!el) return 0;
      try {
        const raw = (el.innerText || el.textContent || '').trim();
        const n = parseInt(raw, 10);
        return isNaN(n) ? 1 : n;
      } catch (_) { return 1; }
    }

    function check() {
      try {
        const titleMatch = document.title.match(/\((\d+)\)/);
        const currentTitleUnread = titleMatch ? parseInt(titleMatch[1]) : 0;
        const dmBadge = document.querySelector([
          'a[href*="/direct/inbox/"] [style*="rgb(255, 48, 64)"]',
          'a[href*="/direct/inbox/"] [aria-label*="unread"]',
          'a[href*="/direct/inbox/"] ._a9-v',
        ].join(','));
        const currentDmCount = parseBadgeCount(dmBadge);
        const notifBadge = document.querySelector([
          'a[href*="/notifications"] [style*="rgb(255, 48, 64)"]',
          'a[href*="/notifications"] [aria-label*="unread"]',
        ].join(','));
        const currentNotifCount = parseBadgeCount(notifBadge);

        if (!initialised) {
          lastDmCount = currentDmCount; lastNotifCount = currentNotifCount;
          lastTitleUnread = currentTitleUnread; initialised = true; return;
        }
        if (Date.now() - startedAt < 6000) {
          lastDmCount = currentDmCount; lastNotifCount = currentNotifCount;
          lastTitleUnread = currentTitleUnread; return;
        }
        if (currentDmCount > lastDmCount && window.flutter_inappwebview) {
          window.flutter_inappwebview.callHandler('FocusGramNotificationChannel', 'DM');
        } else if (currentNotifCount > lastNotifCount && window.flutter_inappwebview) {
          window.flutter_inappwebview.callHandler('FocusGramNotificationChannel', 'Activity');
        }
        lastDmCount = currentDmCount; lastNotifCount = currentNotifCount;
        lastTitleUnread = currentTitleUnread;
      } catch(_) {}
    }
    setTimeout(check, 2000);
    setInterval(check, 1000);
  })();
''';

const String kNotificationBridgeJS = '''
  (function fgNotifBridge() {
    if (!window.Notification || window.__fgNotifBridged) return;
    window.__fgNotifBridged = true;
    const startedAt = Date.now();
    const _N = window.Notification;
    window.Notification = function(title, opts) {
      try {
        if (Date.now() - startedAt < 6000) return new _N(title, opts);
        if (window.flutter_inappwebview) {
          window.flutter_inappwebview.callHandler(
            'FocusGramNotificationChannel',
            title + (opts && opts.body ? ': ' + opts.body : ''),
          );
        }
      } catch(_) {}
      return new _N(title, opts);
    };
    window.Notification.permission = 'granted';
    window.Notification.requestPermission = () => Promise.resolve('granted');
  })();
''';

const String kLinkSanitizationJS = r'''
  (function fgSanitize() {
    if (window.__fgSanitizePatched) return;
    window.__fgSanitizePatched = true;
    const STRIP = [
      'igsh','igshid','fbclid',
      'utm_source','utm_medium','utm_campaign','utm_term','utm_content',
      'ref','s','_branch_match_id','_branch_referrer',
    ];
    function clean(raw) {
      try {
        const u = new URL(raw, location.origin);
        STRIP.forEach(p => u.searchParams.delete(p));
        return u.toString();
      } catch(_) { return raw; }
    }
    if (navigator.share) {
      const _s = navigator.share.bind(navigator);
      navigator.share = function(d) {
        const u = d && d.url ? clean(d.url) : null;
        if (window.flutter_inappwebview && u) {
          window.flutter_inappwebview.callHandler(
            'FocusGramShareChannel',
            JSON.stringify({ url: u, title: (d && d.title) || '' }),
          );
          return Promise.resolve();
        }
        return _s({ ...d, url: u || (d && d.url) });
      };
    }
    document.addEventListener('click', e => {
      const a = e.target && e.target.closest('a[href]');
      if (!a) return;
      const href = a.getAttribute('href');
      if (!href || href.startsWith('#') || href.startsWith('javascript')) return;
      try {
        const u = new URL(href, location.origin);
        if (STRIP.some(p => u.searchParams.has(p))) {
          STRIP.forEach(p => u.searchParams.delete(p));
          a.href = u.toString();
        }
      } catch(_) {}
    }, true);
  })();
''';

// ── InjectionManager class ─────────────────────────────────────────────────

abstract class JsEvaluator {
  Future<void> evaluateJavascript({required String source});
}

class _WebViewJsEvaluator implements JsEvaluator {
  final InAppWebViewController controller;
  _WebViewJsEvaluator(this.controller);

  @override
  Future<void> evaluateJavascript({required String source}) {
    return controller.evaluateJavascript(source: source);
  }
}

class InjectionManager {
  final JsEvaluator _jsEvaluator;
  final SharedPreferences prefs;
  final SessionManager sessionManager;

  SettingsService? _settingsService;

  InjectionManager({
    required InAppWebViewController controller,
    required this.prefs,
    required this.sessionManager,
    JsEvaluator? jsEvaluator,
  }) : _jsEvaluator = jsEvaluator ?? _WebViewJsEvaluator(controller);

  InjectionManager.forTest({
    required JsEvaluator jsEvaluator,
    required this.prefs,
    required this.sessionManager,
  }) : _jsEvaluator = jsEvaluator;

  void setSettingsService(SettingsService settingsService) {
    _settingsService = settingsService;
  }

  /// Runs all post-load JavaScript injections based on current settings.
  Future<void> runAllPostLoadInjections(String url) async {
    if (_settingsService == null) return;

    final settings = _settingsService!;
    final sessionActive = sessionManager.isSessionActive;

    // Get settings values
    // Minimal mode controls all blocking - when enabled, it forces blur and disables
    final blurExplore = settings.blurExplore || settings.minimalModeEnabled;
    final tapToUnblur = settings.tapToUnblur;
    final enableTextSelection = settings.enableTextSelection;

    // Per request: remove ALL “Hide Suggested Posts” behavior/UI/JS injection.
    final hideSuggestedPosts = false;
    final hideLikeCounts = settings.hideLikeCounts;
    final hideFollowerCounts = settings.hideFollowerCounts;
    // Tab hiding is controlled by disableExploreEntirely and disableReelsEntirely
    // These are now only controllable via minimal mode submenu
    final disableExploreEntirely = settings.disableExploreEntirely;
    final disableReelsEntirely = settings.disableReelsEntirely;
    final blockHomeFeedScroll = settings.blockHomeFeedScroll;
    final hideExploreTab = disableExploreEntirely;
    final hideReelsTab = disableReelsEntirely;
    final hideShopTab = settings.hideShopTab;

    final injectionJS = InjectionController.buildInjectionJS(
      sessionActive: sessionActive,
      blurExplore: blurExplore,
      blurReels: false, // Blur reels feature removed
      tapToUnblur: blurExplore && tapToUnblur,
      enableTextSelection: enableTextSelection,
      hideSuggestedPosts: hideSuggestedPosts,
      hideSponsoredPosts: false, // Removed - using V2 DOM Ad Blocker instead
      hideLikeCounts: hideLikeCounts,
      hideFollowerCounts: hideFollowerCounts,
      hideExploreTab: hideExploreTab,
      hideReelsTab: hideReelsTab,
      hideShopTab: hideShopTab,
      disableReelsEntirely: disableReelsEntirely,
      blockHomeFeedScroll: blockHomeFeedScroll,
    );

    try {
      await _jsEvaluator.evaluateJavascript(source: injectionJS);
    } catch (e) {
      // Silently handle injection errors
    }

    // Inject grayscale when active, remove when not active
    if (settings.isGrayscaleActiveNow) {
      try {
        await _jsEvaluator.evaluateJavascript(source: grayscale.kGrayscaleJS);
      } catch (e) {
        // Silently handle injection errors
      }
    } else {
      try {
        await _jsEvaluator.evaluateJavascript(
          source: grayscale.kGrayscaleOffJS,
        );
      } catch (e) {
        // Silently handle injection errors
      }
    }

    // Inject hide like counts JS when enabled
    if (hideLikeCounts) {
      try {
        await _jsEvaluator.evaluateJavascript(
          source: ui_hider.kHideLikeCountsJS,
        );
      } catch (e) {
        // Silently handle injection errors
      }
    }

    // Stories hiding functionality removed per user request
    // No stories overlay injection needed

    // Inject video downloader UI when enabled
    if (settings.videoDownloadEnabled) {
      try {
        await _jsEvaluator.evaluateJavascript(
          source: video_downloader.kVideoDownloadJS,
        );
      } catch (e) {
        // Silently handle injection errors
      }
    }

    // Inject DM Reel blocker when disableReelsEntirely is enabled
    if (disableReelsEntirely) {
      try {
        await _jsEvaluator.evaluateJavascript(
          source: content_disabling.kDmReelBlockerJS,
        );
      } catch (e) {
        // Silently handle injection errors
      }
    }
  }
}
