( function () {
  'use strict';

  var config = window.pdtDesignMidnightFix || {};
  if ( ! config.enabled ) {
    return;
  }

  var textColor = config.textColor || '#f8fafc';
  var darkThreshold = typeof config.darkThreshold === 'number' ? config.darkThreshold : 0.2;
  var contrastThreshold = typeof config.minContrast === 'number' ? config.minContrast : 4.2;
  var containerSelectors = Array.isArray( config.containerSelectors ) && config.containerSelectors.length
    ? config.containerSelectors
    : [
        '.postbox .inside',
        '.stuffbox .inside',
        '.widget-inside',
        '.widgets-holder-wrap',
        '.accordion-section-content',
        '.tabs-panel',
        '.misc-pub-section',
        '.submitbox .inside',
        '.categorydiv div.tabs-panel',
        '.customlinkdiv div.tabs-panel'
      ];

  var animationFrame = null;
  var fixColorSample = null;

  function parseColor( value ) {
    if ( ! value || 'string' !== typeof value ) {
      return null;
    }

    var match = value.trim().match( /^rgba?\(([^)]+)\)$/i );
    if ( ! match ) {
      return null;
    }

    var parts = match[1].split( ',' ).map( function ( part ) {
      return parseFloat( part.trim() );
    } );

    if ( parts.length < 3 || parts.some( function ( part ) { return Number.isNaN( part ); } ) ) {
      return null;
    }

    return {
      r: parts[0],
      g: parts[1],
      b: parts[2],
      a: parts.length > 3 ? parts[3] : 1
    };
  }

  function toLinear( channel ) {
    var value = channel / 255;
    return value <= 0.03928 ? value / 12.92 : Math.pow( ( value + 0.055 ) / 1.055, 2.4 );
  }

  function luminance( color ) {
    return ( 0.2126 * toLinear( color.r ) ) +
      ( 0.7152 * toLinear( color.g ) ) +
      ( 0.0722 * toLinear( color.b ) );
  }

  function contrastRatio( first, second ) {
    var light = Math.max( luminance( first ), luminance( second ) );
    var dark = Math.min( luminance( first ), luminance( second ) );
    return ( light + 0.05 ) / ( dark + 0.05 );
  }

  function getResolvedFixColor() {
    if ( fixColorSample ) {
      return fixColorSample;
    }

    var probe = document.createElement( 'span' );
    probe.style.position = 'absolute';
    probe.style.opacity = '0';
    probe.style.pointerEvents = 'none';
    probe.style.color = textColor;
    document.body.appendChild( probe );
    fixColorSample = parseColor( window.getComputedStyle( probe ).color ) || { r: 248, g: 250, b: 252, a: 1 };
    probe.remove();

    return fixColorSample;
  }

  function getEffectiveBackground( element ) {
    var current = element;

    while ( current && current !== document.documentElement ) {
      var background = parseColor( window.getComputedStyle( current ).backgroundColor );
      if ( background && background.a > 0 ) {
        return background;
      }
      current = current.parentElement;
    }

    return parseColor( window.getComputedStyle( document.body ).backgroundColor ) || { r: 8, g: 17, b: 31, a: 1 };
  }

  function hasOwnText( element ) {
    for ( var i = 0; i < element.childNodes.length; i += 1 ) {
      var node = element.childNodes[i];
      if ( node.nodeType === Node.TEXT_NODE && node.textContent && node.textContent.trim().length ) {
        return true;
      }
    }

    return false;
  }

  function isVisible( element ) {
    var style = window.getComputedStyle( element );
    if ( 'none' === style.display || 'hidden' === style.visibility || parseFloat( style.opacity || '1' ) === 0 ) {
      return false;
    }

    var rect = element.getBoundingClientRect();
    return rect.width > 0 || rect.height > 0;
  }

  function shouldSkip( element ) {
    if ( ! element || element.dataset.pdtMidnightAutofixSkip === '1' ) {
      return true;
    }

    if ( element.closest( '#adminmenu, #wpadminbar, #pdt-wrap, .mce-container iframe, .wp-picker-holder, .iris-picker, .notice, .button, .button-primary, .button-secondary, .page-title-action' ) ) {
      return true;
    }

    if ( element.closest( 'svg, img, button, input, textarea, select, option' ) ) {
      return true;
    }

    if ( element.classList.contains( 'dashicons' ) || element.closest( '.dashicons' ) ) {
      return true;
    }

    return false;
  }

  function shouldFixElement( element ) {
    if ( shouldSkip( element ) || ! hasOwnText( element ) || ! isVisible( element ) ) {
      return false;
    }

    var style = window.getComputedStyle( element );
    var color = parseColor( style.color );
    if ( ! color || color.a === 0 ) {
      return false;
    }

    var background = getEffectiveBackground( element );
    if ( ! background ) {
      return false;
    }

    if ( luminance( background ) > darkThreshold ) {
      return false;
    }

    var currentContrast = contrastRatio( background, color );
    if ( currentContrast >= contrastThreshold ) {
      return false;
    }

    return contrastRatio( background, getResolvedFixColor() ) > currentContrast;
  }

  function applyFix( element ) {
    element.style.setProperty( 'color', textColor, 'important' );
    element.dataset.pdtMidnightAutofix = '1';
  }

  function scanWithin( container ) {
    if ( ! container || ! container.querySelectorAll ) {
      return;
    }

    var elements = container.querySelectorAll( '*' );
    for ( var index = 0; index < elements.length; index += 1 ) {
      if ( shouldFixElement( elements[index] ) ) {
        applyFix( elements[index] );
      }
    }
  }

  function scanDocument() {
    for ( var i = 0; i < containerSelectors.length; i += 1 ) {
      var containers = document.querySelectorAll( containerSelectors[i] );
      for ( var j = 0; j < containers.length; j += 1 ) {
        scanWithin( containers[j] );
      }
    }
  }

  function scheduleScan() {
    if ( animationFrame ) {
      window.cancelAnimationFrame( animationFrame );
    }

    animationFrame = window.requestAnimationFrame( function () {
      animationFrame = null;
      scanDocument();
    } );
  }

  if ( document.readyState === 'loading' ) {
    document.addEventListener( 'DOMContentLoaded', scheduleScan );
  } else {
    scheduleScan();
  }

  window.addEventListener( 'load', scheduleScan );
  document.addEventListener( 'click', scheduleScan, true );

  if ( 'MutationObserver' in window ) {
    var observer = new MutationObserver( scheduleScan );
    observer.observe( document.body, {
      childList: true,
      subtree: true
    } );
  }
}() );
