/**
 * Google IMA Ads Manager
 * Supports ALL Google ad types:
 * - Pre-roll (before video)
 * - Mid-roll (during video)
 * - Post-roll (after video)
 * - Overlay ads (non-linear)
 * - Companion ads (sidebar/banner)
 * - Bumper ads (short 6s ads)
 * - Skippable & non-skippable ads
 */

export interface GoogleAdsConfig {
  // Ad tag URL (VAST/VMAP)
  adTagUrl: string;

  // Optional: Specific ad break times (for mid-rolls)
  // If not provided, uses VMAP schedule from ad server
  midrollTimes?: number[];  // e.g., [30, 60, 120] = ads at 30s, 60s, 120s

  // Periodic ad breaks (for live streams or automatic scheduling)
  liveAdBreakMode?: 'periodic' | 'manual';  // 'periodic' = auto-schedule at intervals, 'manual' = use midrollTimes
  periodicAdInterval?: number;  // Interval in seconds between ads (e.g., 30 = ad every 30 seconds)
  syncToLiveEdge?: boolean;  // For live streams: sync back to live edge after ad
  pauseStreamDuringAd?: boolean;  // Pause underlying stream during ad playback
  liveEdgeOffset?: number;  // Seconds behind live edge to resume at (default: 3)

  // Companion ad containers
  companionAdSlots?: Array<{
    containerId: string;  // HTML element ID
    width: number;
    height: number;
  }>;

  // Callbacks
  onAdStart?: () => void;
  onAdEnd?: () => void;
  onAdError?: (error: any) => void;
  onAllAdsComplete?: () => void;
  onAdCuePoints?: (cuePoints: number[]) => void;  // Called when ad schedule is loaded
}

export class GoogleAdsManager {
  private video: HTMLVideoElement;
  private adContainer: HTMLElement;
  private config: GoogleAdsConfig;
  private adsManager: any = null;
  private adsLoader: any = null;
  private adDisplayContainer: any = null;
  private isAdPlaying = false;
  private isMuted = true;
  private unmuteButton: HTMLElement | null = null;
  private adProgressBar: HTMLElement | null = null;
  private adProgressInterval: any = null;

  // Periodic ad scheduling
  private lastAdTime = 0;
  private periodicAdCheckInterval: any = null;
  private pendingAdRequest = false;

  // Bound event handler references for proper cleanup
  private focusHandler: () => void;
  private visibilityHandler: () => void;
  private timeupdateHandler: (() => void) | null = null;
  private volumechangeHandler: (() => void) | null = null;

  // Mid-roll tracking for explicit midrollTimes
  private triggeredMidrollTimes: Set<number> = new Set();

  constructor(video: HTMLVideoElement, adContainer: HTMLElement, config: GoogleAdsConfig) {
    this.video = video;
    this.adContainer = adContainer;
    this.config = config;

    // Bind handlers so they can be removed on destroy
    this.focusHandler = () => {
      if (this.isAdPlaying) {
        console.log('Window focused - resuming ad playback');
        this.resumeAdPlayback();
        setTimeout(() => this.resumeAdPlayback(), 200);
      }
    };
    this.visibilityHandler = () => {
      if (!document.hidden && this.isAdPlaying) {
        console.log('Tab became visible - resuming ad playback');
        this.resumeAdPlayback();
      }
    };

    // Add focus handler to resume ads after click-through
    this.setupFocusHandler();
  }

  /**
   * Setup focus handler to resume ads when window regains focus
   */
  private setupFocusHandler(): void {
    window.addEventListener('focus', this.focusHandler);
    document.addEventListener('visibilitychange', this.visibilityHandler);
  }

  /**
   * Initialize ads system
   */
  async initialize(): Promise<void> {
    try {
      await this.loadIMASDK();
      this.setupAdsLoader();
    } catch (error) {
      console.error('Failed to initialize Google Ads:', error);
      this.config.onAdError?.(error);
    }
  }

  /**
   * Load Google IMA SDK
   */
  private loadIMASDK(): Promise<void> {
    return new Promise((resolve, reject) => {
      if ((window as any).google?.ima) {
        resolve();
        return;
      }

      const script = document.createElement('script');
      script.src = 'https://imasdk.googleapis.com/js/sdkloader/ima3.js';
      script.async = true;
      script.onload = () => resolve();
      script.onerror = () => reject(new Error('Failed to load Google IMA SDK'));
      document.head.appendChild(script);
    });
  }

  /**
   * Setup ads loader
   */
  private setupAdsLoader(): void {
    const google = (window as any).google;

    // Validate ad container has non-zero dimensions
    const rect = this.adContainer.getBoundingClientRect();
    if (rect.width === 0 || rect.height === 0) {
      console.warn('⚠️ Ad container has zero dimensions:', rect.width, 'x', rect.height);
      console.warn('IMA UI may not render correctly. Ensure container is visible before initialization.');
    }

    // Create ad display container
    this.adDisplayContainer = new google.ima.AdDisplayContainer(
      this.adContainer,
      this.video
    );

    // Create ads loader
    this.adsLoader = new google.ima.AdsLoader(this.adDisplayContainer);

    // Register for ads loaded event
    this.adsLoader.addEventListener(
      google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,
      (event: any) => this.onAdsManagerLoaded(event),
      false
    );

    // Register for error event
    this.adsLoader.addEventListener(
      google.ima.AdErrorEvent.Type.AD_ERROR,
      (event: any) => this.onAdError(event),
      false
    );

    // Signal when video content completes (for post-rolls)
    this.video.addEventListener('ended', () => {
      if (!this.isAdPlaying) {
        this.adsLoader?.contentComplete();
      }
    });

    // Setup mid-roll triggers for explicitly provided midrollTimes
    this.setupMidrollTriggers();
  }

  /**
   * Setup timeupdate-based mid-roll triggers for explicit midrollTimes.
   * Without this, midrollTimes only shows visual markers but never fires actual ads.
   */
  private setupMidrollTriggers(): void {
    if (!this.config.midrollTimes || this.config.midrollTimes.length === 0) {
      return;
    }

    console.log(`📺 Setting up mid-roll triggers for times: ${this.config.midrollTimes.join(', ')}s`);

    this.timeupdateHandler = () => {
      if (this.isAdPlaying || this.pendingAdRequest) return;

      const currentTime = this.video.currentTime;
      for (const triggerTime of this.config.midrollTimes!) {
        // Trigger when currentTime crosses the target within a 1-second window
        if (!this.triggeredMidrollTimes.has(triggerTime) && currentTime >= triggerTime && currentTime < triggerTime + 2) {
          console.log(`⏰ Mid-roll triggered at ${currentTime.toFixed(1)}s (scheduled: ${triggerTime}s)`);
          this.triggeredMidrollTimes.add(triggerTime);
          this.pendingAdRequest = true;
          this.lastAdTime = currentTime;
          if (this.config.pauseStreamDuringAd && !this.video.paused) {
            this.video.pause();
          }
          this.requestAds();
          break;
        }
      }
    };

    this.video.addEventListener('timeupdate', this.timeupdateHandler);
  }

  /**
   * Setup periodic ad breaks (for live streams or auto-scheduling)
   */
  setupPeriodicAds(): void {
    // Only setup if periodic mode is enabled
    if (this.config.liveAdBreakMode !== 'periodic' || !this.config.periodicAdInterval) {
      return;
    }

    // Guard: only one interval allowed — each requestAds() cycle calls onAdsManagerLoaded()
    // which calls setupPeriodicAds() again; without this guard, intervals multiply.
    if (this.periodicAdCheckInterval !== null) {
      return;
    }

    console.log(`📺 Setting up periodic ads: interval=${this.config.periodicAdInterval}s`);

    // Check every second if we should trigger an ad
    this.periodicAdCheckInterval = setInterval(() => {
      // Skip if ad is already playing or pending
      if (this.isAdPlaying || this.pendingAdRequest) {
        return;
      }

      const currentTime = this.video.currentTime;
      const interval = this.config.periodicAdInterval || 30;

      // Check if enough time has passed since last ad
      if (currentTime - this.lastAdTime >= interval && currentTime > 0) {
        console.log(`⏰ Periodic ad triggered at ${currentTime.toFixed(1)}s (interval: ${interval}s)`);
        this.triggerPeriodicAd();
      }
    }, 1000); // Check every second

    console.log('✅ Periodic ad scheduling enabled');
  }

  /**
   * Trigger a periodic ad break
   */
  private triggerPeriodicAd(): void {
    if (this.pendingAdRequest || this.isAdPlaying) {
      return;
    }

    this.pendingAdRequest = true;
    this.lastAdTime = this.video.currentTime;

    console.log('🎬 Triggering periodic ad break...');

    // Pause video if configured
    if (this.config.pauseStreamDuringAd && !this.video.paused) {
      this.video.pause();
    }

    // Request a new ad
    this.requestAds();
  }

  /**
   * Request ads
   */
  requestAds(): void {
    const google = (window as any).google;

    // Guard: don't call on a destroyed instance
    if (!this.adsLoader) {
      console.warn('requestAds() called but adsLoader is null (destroyed?)');
      this.pendingAdRequest = false;
      return;
    }

    try {
      const adsRequest = new google.ima.AdsRequest();
      adsRequest.adTagUrl = this.config.adTagUrl;

      // Set video dimensions
      adsRequest.linearAdSlotWidth = this.video.clientWidth;
      adsRequest.linearAdSlotHeight = this.video.clientHeight;
      adsRequest.nonLinearAdSlotWidth = this.video.clientWidth;
      adsRequest.nonLinearAdSlotHeight = Math.floor(this.video.clientHeight / 3);

      // Set companion ad slots if provided
      if (this.config.companionAdSlots && this.config.companionAdSlots.length > 0) {
        const companionAdSlots = this.config.companionAdSlots.map(slot => {
          const container = document.getElementById(slot.containerId);
          if (!container) return null;
          return new google.ima.CompanionAdSelectionSettings();
        }).filter(Boolean);
        if (companionAdSlots.length > 0) {
          adsRequest.companionSlots = companionAdSlots;
        }
      }

      // Chrome autoplay policy: ads must start muted for autoplay to work
      // User can unmute after ad starts
      adsRequest.setAdWillAutoPlay(true);
      adsRequest.setAdWillPlayMuted(true); // Start muted for Chrome compatibility

      // Request ads
      this.adsLoader.requestAds(adsRequest);
    } catch (error) {
      console.error('Error requesting ads:', error);
      // Reset pending flag so future ad breaks are not permanently blocked
      this.pendingAdRequest = false;
      this.config.onAdError?.(error);
    }
  }

  /**
   * Initialize ad display container (must be called on user gesture)
   */
  initAdDisplayContainer(): void {
    try {
      this.adDisplayContainer?.initialize();
    } catch (error) {
      console.warn('Ad display container already initialized');
    }
  }

  /**
   * Handle ads manager loaded
   */
  private onAdsManagerLoaded(event: any): void {
    const google = (window as any).google;

    // Setup ads rendering settings
    const adsRenderingSettings = new google.ima.AdsRenderingSettings();
    adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true;
    adsRenderingSettings.enablePreloading = true;
    // Start muted for Chrome autoplay compatibility - user can unmute via button
    adsRenderingSettings.mute = this.video.muted;

    // CRITICAL: Don't set uiElements at all - let IMA use its defaults
    // Setting uiElements (even to []) can disable UI in some IMA SDK versions
    // By not setting it, IMA SDK will render its default UI overlay
    // This includes: Advertisement label, countdown timer, learn more button, etc.
    // Reference: https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/js/google.ima.AdsRenderingSettings#uiElements

    // NOTE: If uiElements is left unset, IMA SDK version determines default behavior
    // Most modern IMA SDK versions (3.x+) show all UI elements by default

    // Enable styled linear ads for better UI rendering
    adsRenderingSettings.useStyledLinearAds = true;

    // Check IMA SDK version and available UI elements
    console.log('📊 IMA SDK Info:', {
      version: google.ima.VERSION || 'unknown',
      hasUiElements: !!google.ima.UiElements,
      availableUiElements: google.ima.UiElements ? Object.keys(google.ima.UiElements) : []
    });

    console.log('✅ IMA AdsRenderingSettings configured:', {
      uiElements: adsRenderingSettings.uiElements || 'not set (using IMA defaults)',
      enablePreloading: adsRenderingSettings.enablePreloading,
      useStyledLinearAds: adsRenderingSettings.useStyledLinearAds,
      mute: adsRenderingSettings.mute,
      restoreCustomPlaybackStateOnAdBreakComplete: adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete
    });

    // Get the ads manager
    this.adsManager = event.getAdsManager(this.video, adsRenderingSettings);

    // Extract cue points (ad break times) from VMAP/ad server
    try {
      const cuePoints = this.adsManager.getCuePoints();
      if (cuePoints && cuePoints.length > 0) {
        // Process all cue points including pre-roll (0) and post-roll (-1)
        const allCuePoints = cuePoints.map((time: number) => {
          // Convert special values to actual times
          if (time === 0) return 0;           // Pre-roll at start
          if (time === -1) return -1;         // Post-roll (will be converted to video duration later)
          return time;                         // Mid-roll at specific time
        });

        console.log('📍 Ad cue points detected (pre/mid/post):', allCuePoints);

        // Notify callback with all cue points
        if (this.config.onAdCuePoints) {
          this.config.onAdCuePoints(allCuePoints);
        }
      }
    } catch (error) {
      console.warn('Could not extract ad cue points:', error);
    }

    // Setup ads manager event listeners
    this.setupAdsManagerListeners();

    try {
      // Initialize ads manager
      this.adsManager.init(
        this.video.clientWidth,
        this.video.clientHeight,
        google.ima.ViewMode.NORMAL
      );

      // Start ads
      this.adsManager.start();

      // Setup periodic ad scheduling if enabled (guard inside prevents duplicate intervals)
      this.setupPeriodicAds();
    } catch (error) {
      console.error('Error starting ads:', error);
      // Reset state so the pipeline is not permanently stuck
      this.pendingAdRequest = false;
      this.isAdPlaying = false;
      this.video.play().catch(() => { });
    }
  }

  /**
   * Setup ads manager event listeners
   */
  private setupAdsManagerListeners(): void {
    const google = (window as any).google;

    // Content pause - ad is about to play
    this.adsManager.addEventListener(
      google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED,
      () => {
        console.log('Ad: Content paused');
        this.isAdPlaying = true;
        this.pendingAdRequest = false; // Reset pending flag
        this.video.pause();

        // Force ad container visibility and z-index
        if (this.adContainer) {
          this.adContainer.style.visibility = 'visible';
          this.adContainer.style.opacity = '1';
          this.adContainer.style.pointerEvents = 'auto';
          this.adContainer.style.zIndex = '2147483647';
          console.log('✅ Ad container visibility enforced');

          // Diagnostic: Check for IMA UI elements after a short delay
          setTimeout(() => {
            const imaElements = this.adContainer.querySelectorAll('[class*="ima-"], [id*="ima-"]');
            const allDivs = this.adContainer.querySelectorAll('div');

            // Find and force-show any "Advertisement" labels
            let advertisementLabelFound = false;
            allDivs.forEach((div: HTMLElement) => {
              const text = div.textContent?.trim() || '';
              if (text === 'Advertisement' || text === 'Ad' || text.startsWith('Advertisement')) {
                console.log('📢 Found Advertisement label:', {
                  text,
                  visible: div.offsetWidth > 0 && div.offsetHeight > 0,
                  display: getComputedStyle(div).display,
                  position: getComputedStyle(div).position
                });
                // Force it to be visible
                div.style.display = 'block';
                div.style.visibility = 'visible';
                div.style.opacity = '1';
                div.style.position = 'absolute';
                div.style.top = '10px';
                div.style.left = '10px';
                div.style.zIndex = '999999';
                div.style.color = 'white';
                div.style.background = 'rgba(0, 0, 0, 0.6)';
                div.style.padding = '4px 8px';
                div.style.fontSize = '12px';
                div.style.fontFamily = 'Arial, sans-serif';
                advertisementLabelFound = true;
              }
            });

            console.log('🔍 IMA UI Diagnostic:', {
              totalDivs: allDivs.length,
              imaElements: imaElements.length,
              containerChildren: this.adContainer.children.length,
              adContainerSize: `${this.adContainer.offsetWidth}x${this.adContainer.offsetHeight}`,
              advertisementLabelFound
            });

            if (!advertisementLabelFound) {
              console.warn('⚠️ Advertisement label not found in DOM - creating custom overlay');

              // Create custom "Advertisement" label for compliance
              const adLabel = document.createElement('div');
              adLabel.id = 'uvf-custom-ad-label';
              adLabel.textContent = 'Advertisement';
              adLabel.style.cssText = `
                position: absolute !important;
                top: 10px !important;
                left: 10px !important;
                z-index: 2147483647 !important;
                color: white !important;
                background: rgba(0, 0, 0, 0.7) !important;
                padding: 4px 10px !important;
                font-size: 12px !important;
                font-family: Arial, Roboto, sans-serif !important;
                font-weight: 500 !important;
                letter-spacing: 0.5px !important;
                border-radius: 2px !important;
                pointer-events: none !important;
                user-select: none !important;
              `;
              this.adContainer.appendChild(adLabel);
              console.log('✅ Custom Advertisement label created and displayed');
            }

            if (imaElements.length === 0) {
              console.warn('⚠️ No IMA UI elements found! UI may not be rendering.');
              console.warn('This could mean: 1) Ad creative has no UI, 2) uiElements config issue, 3) IMA SDK version issue');
            } else {
              console.log('✅ IMA UI elements detected:', Array.from(imaElements).map(el => el.className || el.id));
            }
          }, 500);
        }

        // Strict enforcement: Prevent video from playing during ads
        const preventPlayDuringAd = (e: Event) => {
          if (this.isAdPlaying) {
            e.preventDefault();
            this.video.pause();
            console.warn('Blocked video play attempt during ad');
          }
        };

        // Add play event listener to block any play attempts
        this.video.addEventListener('play', preventPlayDuringAd);

        // Store cleanup function to remove listener later
        (this.video as any).__adPlayBlocker = preventPlayDuringAd;

        // Sync player volume/mute changes to IMA during ad playback
        this.volumechangeHandler = () => {
          if (!this.adsManager || !this.isAdPlaying) return;
          const vol = this.video.muted ? 0 : this.video.volume;
          this.adsManager.setVolume(vol);
          const wasMuted = this.isMuted;
          this.isMuted = this.video.muted || this.video.volume === 0;
          if (wasMuted !== this.isMuted) {
            this.updateMuteButtonUI();
          }
        };
        this.video.addEventListener('volumechange', this.volumechangeHandler);

        this.config.onAdStart?.();
      }
    );

    // Content resume - ad finished
    this.adsManager.addEventListener(
      google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED,
      () => {
        console.log('Ad: Content resume');
        this.isAdPlaying = false;

        // Remove custom Advertisement label
        const customLabel = this.adContainer.querySelector('#uvf-custom-ad-label');
        if (customLabel) {
          customLabel.remove();
        }

        // Hide ad progress bar
        this.hideAdProgressBar();

        // Remove play blocker
        const preventPlayDuringAd = (this.video as any).__adPlayBlocker;
        if (preventPlayDuringAd) {
          this.video.removeEventListener('play', preventPlayDuringAd);
          delete (this.video as any).__adPlayBlocker;
        }

        // Remove volume sync listener
        if (this.volumechangeHandler) {
          this.video.removeEventListener('volumechange', this.volumechangeHandler);
          this.volumechangeHandler = null;
        }

        this.config.onAdEnd?.();
        this.video.play().catch(() => { });
      }
    );

    // Ad started
    this.adsManager.addEventListener(
      google.ima.AdEvent.Type.STARTED,
      (event: any) => {
        const ad = event.getAd();
        console.log('Ad started:', {
          type: ad.isLinear() ? 'Linear (video)' : 'Non-linear (overlay)',
          duration: ad.getDuration(),
          skippable: ad.getSkipTimeOffset() !== -1,
          title: ad.getTitle(),
        });

        // Sync ads mute state with video element
        this.isMuted = this.video.muted;
        console.log(`Ad started - video.muted=${this.video.muted}, isMuted=${this.isMuted}`);

        // Check if video is actually muted and show unmute button only then
        if (this.isMuted) {
          this.showUnmuteButton();
        }

        // Show ad progress bar
        this.showAdProgressBar(ad.getDuration());

      }
    );

    // Ad completed
    this.adsManager.addEventListener(
      google.ima.AdEvent.Type.COMPLETE,
      () => {
        console.log('Ad completed');
      }
    );

    // All ads completed
    this.adsManager.addEventListener(
      google.ima.AdEvent.Type.ALL_ADS_COMPLETED,
      () => {
        console.log('All ads completed');
        this.config.onAllAdsComplete?.();
      }
    );

    // Ad error
    this.adsManager.addEventListener(
      google.ima.AdErrorEvent.Type.AD_ERROR,
      (event: any) => this.onAdError(event)
    );

    // Ad skipped
    this.adsManager.addEventListener(
      google.ima.AdEvent.Type.SKIPPED,
      () => {
        console.log('Ad skipped by user');
      }
    );

    // Ad paused (by click-through)
    this.adsManager.addEventListener(
      google.ima.AdEvent.Type.PAUSED,
      () => {
        console.log('Ad paused (likely from click-through)');
        // Don't mark as not playing - keep isAdPlaying true so we can resume
      }
    );

    // Ad playing (resume after pause)
    this.adsManager.addEventListener(
      google.ima.AdEvent.Type.PLAYING,
      () => {
        console.log('Ad resumed playing');
      }
    );
  }

  /**
   * Handle ad error
   */
  private onAdError(event: any): void {
    const error = event.getError?.();
    console.error('Ad error:', error?.getMessage?.() || error);

    this.config.onAdError?.(error);

    // Destroy ads manager on error
    if (this.adsManager) {
      this.adsManager.destroy();
      this.adsManager = null;
    }

    // Reset all ad state
    this.isAdPlaying = false;
    this.pendingAdRequest = false;

    // Remove the play blocker if it was installed (would block all future playback otherwise)
    const blocker = (this.video as any).__adPlayBlocker;
    if (blocker) {
      this.video.removeEventListener('play', blocker);
      delete (this.video as any).__adPlayBlocker;
    }

    // Hide unmute button if showing
    this.hideUnmuteButton();

    // Resume content playback
    this.video.play().catch(() => { });
  }

  /**
   * Pause ad
   */
  pause(): void {
    if (this.adsManager && this.isAdPlaying) {
      this.adsManager.pause();
    }
  }

  /**
   * Resume ad
   */
  resume(): void {
    if (this.adsManager && this.isAdPlaying) {
      this.adsManager.resume();
    }
  }

  /**
   * Skip ad (if skippable)
   */
  skip(): void {
    if (this.adsManager) {
      this.adsManager.skip();
    }
  }

  /**
   * Resize ads - with enhanced fullscreen support
   */
  resize(width: number, height: number, viewMode?: any): void {
    const google = (window as any).google;
    if (this.adsManager && google && google.ima) {
      const mode = viewMode || google.ima.ViewMode.NORMAL;

      console.log(`📐 Resizing ads: ${width}x${height}, ViewMode: ${mode === google.ima.ViewMode.FULLSCREEN ? 'FULLSCREEN' : 'NORMAL'}`);

      // Force ad container dimensions in fullscreen
      if (this.adContainer && mode === google.ima.ViewMode.FULLSCREEN) {
        this.adContainer.style.position = 'fixed';
        this.adContainer.style.top = '0';
        this.adContainer.style.left = '0';
        this.adContainer.style.width = `${width}px`;
        this.adContainer.style.height = `${height}px`;
        this.adContainer.style.zIndex = '2147483647';
        console.log('✅ Ad container forced to fullscreen dimensions');
      }

      this.adsManager.resize(width, height, mode);
    }
  }

  /**
   * Set volume
   */
  setVolume(volume: number): void {
    if (this.adsManager) {
      this.adsManager.setVolume(volume);
    }
  }

  /**
   * Check if ad is currently playing
   */
  isPlayingAd(): boolean {
    return this.isAdPlaying;
  }

  /**
   * Show unmute button overlay (matching player UI style)
   */
  private showUnmuteButton(): void {
    // Remove existing button if any
    if (this.unmuteButton) {
      this.unmuteButton.remove();
    }

    // Create unmute button (matching WebPlayer.ts style)
    this.unmuteButton = document.createElement('button');
    this.unmuteButton.id = 'ad-unmute-btn';
    this.unmuteButton.className = 'uvf-unmute-btn';
    this.unmuteButton.setAttribute('aria-label', 'Tap to unmute ad');
    this.unmuteButton.innerHTML = `
      <svg viewBox="0 0 24 24" class="uvf-unmute-icon">
        <path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"/>
      </svg>
      <span class="uvf-unmute-text">Tap to unmute</span>
    `;

    // Click handler to unmute
    this.unmuteButton.addEventListener('click', (e) => {
      e.stopPropagation();
      this.toggleAdMute();
    });

    // Add styles if not already added
    if (!document.getElementById('uvf-unmute-styles')) {
      const style = document.createElement('style');
      style.id = 'uvf-unmute-styles';
      style.textContent = `
        .uvf-unmute-btn {
          position: absolute !important;
          bottom: 80px !important;
          left: 20px !important;
          z-index: 1000 !important;
          display: flex !important;
          align-items: center !important;
          gap: 8px !important;
          padding: 12px 16px !important;
          background: rgba(0, 0, 0, 0.8) !important;
          border: none !important;
          border-radius: 4px !important;
          color: white !important;
          font-size: 14px !important;
          font-weight: 500 !important;
          cursor: pointer !important;
          transition: all 0.2s ease !important;
          backdrop-filter: blur(10px) !important;
          -webkit-backdrop-filter: blur(10px) !important;
          animation: uvf-unmute-pulse 2s ease-in-out infinite !important;
        }
        
        .uvf-unmute-btn:hover {
          background: rgba(0, 0, 0, 0.9) !important;
          transform: scale(1.05) !important;
        }
        
        .uvf-unmute-btn:active {
          transform: scale(0.95) !important;
        }
        
        .uvf-unmute-icon {
          width: 20px !important;
          height: 20px !important;
          fill: white !important;
        }
        
        .uvf-unmute-text {
          white-space: nowrap !important;
        }
        
        @keyframes uvf-unmute-pulse {
          0%, 100% {
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3) !important;
          }
          50% {
            box-shadow: 0 2px 16px rgba(255, 255, 255, 0.2) !important;
          }
        }
        
        @media (max-width: 767px) {
          .uvf-unmute-btn {
            bottom: 70px !important;
            left: 50% !important;
            transform: translateX(-50%) !important;
            padding: 10px 14px !important;
            font-size: 13px !important;
          }
          
          .uvf-unmute-btn:hover {
            transform: translateX(-50%) scale(1.05) !important;
          }
        }

        /* Protect IMA native UI elements from being hidden by parent application CSS */
        .uvf-ad-container [class*="ima-"],
        .uvf-ad-container [id*="ima-"] {
          visibility: visible !important;
          opacity: 1 !important;
        }

        /* Ensure IMA control containers are visible */
        .uvf-ad-container .ima-ad-container,
        .uvf-ad-container .ima-controls-div,
        .uvf-ad-container .ima-countdown-div,
        .uvf-ad-container .ima-text-div {
          display: block !important;
          visibility: visible !important;
          opacity: 1 !important;
          pointer-events: auto !important;
        }

        /* CRITICAL: Force Advertisement label visibility (usually top-left) */
        .uvf-ad-container .ima-ad-container [class*="text"],
        .uvf-ad-container .ima-ad-container [class*="label"],
        .uvf-ad-container .ima-ad-container [class*="attribution"] {
          display: block !important;
          visibility: visible !important;
          opacity: 1 !important;
          position: relative !important;
          z-index: 999999 !important;
        }

        /* CRITICAL: Force countdown timer visibility */
        .uvf-ad-container .ima-ad-container [class*="countdown"],
        .uvf-ad-container .ima-ad-container [class*="time"],
        .uvf-ad-container .ima-ad-container [class*="remaining"] {
          display: block !important;
          visibility: visible !important;
          opacity: 1 !important;
          position: relative !important;
          z-index: 999999 !important;
        }

        /* Force all text elements in ad container to be visible */
        .uvf-ad-container * {
          max-height: none !important;
          max-width: none !important;
        }

        /* CRITICAL: Advertisement label - typically top-left corner */
        /* This is required by Google Ads policy and FTC regulations */
        .uvf-ad-container div[style*="top"][style*="left"] {
          display: block !important;
          visibility: visible !important;
          opacity: 1 !important;
        }

        /* Force any element containing "Advertisement" or "Ad" text to show */
        .uvf-ad-container div:has-text("Advertisement"),
        .uvf-ad-container div:has-text("Ad ·"),
        .uvf-ad-container span:has-text("Advertisement") {
          display: block !important;
          visibility: visible !important;
          opacity: 1 !important;
          color: white !important;
          background: rgba(0, 0, 0, 0.6) !important;
          padding: 4px 8px !important;
        }
      `;
      document.head.appendChild(style);
    }

    // Add to ad container
    this.adContainer.appendChild(this.unmuteButton);
    console.log('Unmute button displayed (matching player style)');
  }

  /**
   * Toggle ad mute state. Restores original volume on unmute; toggles button icon.
   */
  private toggleAdMute(): void {
    this.isMuted = !this.isMuted;

    if (this.adsManager) {
      // Restore actual player volume on unmute instead of jumping to 100%
      this.adsManager.setVolume(this.isMuted ? 0 : (this.video.volume || 1));
      console.log(`Ad ${this.isMuted ? 'muted' : 'unmuted'}`);
    }

    // Sync mute state with video element (fires volumechangeHandler — harmless)
    this.video.muted = this.isMuted;

    // Toggle button icon so user can always re-mute/re-unmute
    this.updateMuteButtonUI();
  }

  /**
   * Update the mute toggle button icon/label to reflect current isMuted state.
   * Creates the button if muted and not yet shown; keeps it visible when unmuted
   * so the user can re-mute.
   */
  private updateMuteButtonUI(): void {
    if (!this.unmuteButton) {
      if (this.isMuted) this.showUnmuteButton();
      return;
    }

    if (this.isMuted) {
      this.unmuteButton.setAttribute('aria-label', 'Tap to unmute ad');
      this.unmuteButton.innerHTML = `
        <svg viewBox="0 0 24 24" class="uvf-unmute-icon">
          <path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"/>
        </svg>
        <span class="uvf-unmute-text">Tap to unmute</span>
      `;
    } else {
      // Ad is now unmuted — hide the overlay entirely, never show "Tap to mute"
      this.hideUnmuteButton();
    }
  }

  /**
   * Resume ad playback after click-through.
   * Only calls adsManager.resume() — do NOT call video.play() directly here because
   * the __adPlayBlocker listener installed in CONTENT_PAUSE_REQUESTED would immediately
   * re-pause the video element, defeating the resume.  IMA SDK owns the video element
   * during ad playback and handles resumption internally via adsManager.resume().
   */
  private resumeAdPlayback(): void {
    try {
      if (!this.adsManager || !this.isAdPlaying) {
        return;
      }

      console.log('Attempting to resume ad playback...');

      try {
        this.adsManager.resume();
        console.log('✅ Ad resume() called');
      } catch (e) {
        console.warn('resume() failed:', e);
      }
    } catch (error) {
      console.error('Error resuming ad playback:', error);
    }
  }

  /**
   * Hide unmute button
   */
  private hideUnmuteButton(): void {
    if (this.unmuteButton) {
      this.unmuteButton.remove();
      this.unmuteButton = null;
    }
  }

  /**
   * Show ad progress bar (read-only visual indicator)
   */
  private showAdProgressBar(duration: number): void {
    // Remove existing progress bar if any
    this.hideAdProgressBar();

    // Create progress bar container
    const container = document.createElement('div');
    container.id = 'uvf-ad-progress-container';
    container.style.cssText = `
      position: absolute !important;
      bottom: 0px !important;
      left: 0px !important;
      right: 0px !important;
      height: 4px !important;
      background: rgba(0, 0, 0, 0.4) !important;
      overflow: hidden !important;
      z-index: 2147483646 !important;
      pointer-events: none !important;
    `;

    // Create progress bar fill
    const fill = document.createElement('div');
    fill.id = 'uvf-ad-progress-fill';
    fill.style.cssText = `
      position: absolute !important;
      left: 0 !important;
      top: 0 !important;
      height: 100% !important;
      width: 0% !important;
      background: #FFC107 !important;
      box-shadow: 0 0 8px rgba(255, 193, 7, 0.6) !important;
      transition: width 0.1s linear !important;
    `;

    container.appendChild(fill);
    this.adContainer.appendChild(container);
    this.adProgressBar = container;

    console.log('✅ Ad progress bar created');

    // Update progress every 100ms
    let currentTime = 0;
    this.adProgressInterval = setInterval(() => {
      if (!this.adsManager || !this.isAdPlaying) {
        this.hideAdProgressBar();
        return;
      }

      try {
        // Get current ad time from IMA SDK
        const ad = this.adsManager.getCurrentAd();
        if (ad) {
          currentTime = this.adsManager.getRemainingTime();
          const elapsed = duration - currentTime;
          const progress = Math.min(100, Math.max(0, (elapsed / duration) * 100));

          const fillEl = document.getElementById('uvf-ad-progress-fill');
          if (fillEl) {
            fillEl.style.width = `${progress}%`;
          }
        }
      } catch (e) {
        // Silently handle errors (ad might have ended)
      }
    }, 100);
  }

  /**
   * Hide ad progress bar
   */
  private hideAdProgressBar(): void {
    if (this.adProgressInterval) {
      clearInterval(this.adProgressInterval);
      this.adProgressInterval = null;
    }

    if (this.adProgressBar) {
      this.adProgressBar.remove();
      this.adProgressBar = null;
    }
  }

  /**
   * Cleanup
   */
  destroy(): void {
    this.hideUnmuteButton();
    this.hideAdProgressBar();

    // Remove focus/visibility handlers
    window.removeEventListener('focus', this.focusHandler);
    document.removeEventListener('visibilitychange', this.visibilityHandler);

    // Remove timeupdate mid-roll handler
    if (this.timeupdateHandler) {
      this.video.removeEventListener('timeupdate', this.timeupdateHandler);
      this.timeupdateHandler = null;
    }

    // Remove volume sync handler if ad was destroyed mid-playback
    if (this.volumechangeHandler) {
      this.video.removeEventListener('volumechange', this.volumechangeHandler);
      this.volumechangeHandler = null;
    }

    // Remove play blocker if lingering
    const blocker = (this.video as any).__adPlayBlocker;
    if (blocker) {
      this.video.removeEventListener('play', blocker);
      delete (this.video as any).__adPlayBlocker;
    }

    // Clear periodic ad interval
    if (this.periodicAdCheckInterval) {
      clearInterval(this.periodicAdCheckInterval);
      this.periodicAdCheckInterval = null;
      console.log('✅ Periodic ad scheduling stopped');
    }

    if (this.adsManager) {
      this.adsManager.destroy();
      this.adsManager = null;
    }

    if (this.adsLoader) {
      this.adsLoader.destroy();
      this.adsLoader = null;
    }

    this.isAdPlaying = false;
    this.pendingAdRequest = false;
    this.triggeredMidrollTimes.clear();
  }
}
