/**
 * Outputs Javascript to handle California IP detection, consent modal, and setting of default cookies.
 */
( function () {
	/* global ccpaSettings */

	// Minimal Mozilla Cookie library.
	// https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie/Simple_document.cookie_framework
	var cookieLib = {
		getItem: function ( e ) {
			return (
				( e &&
					decodeURIComponent(
						document.cookie.replace(
							new RegExp(
								'(?:(?:^|.*;)\\s*' +
									encodeURIComponent( e ).replace( /[\-\.\+\*]/g, '\\$&' ) +
									'\\s*\\=\\s*([^;]*).*$)|^.*$'
							),
							'$1'
						)
					) ) ||
				null
			);
		},
		setItem: function ( e, o, n, t, r, i ) {
			if ( ! e || /^(?:expires|max\-age|path|domain|secure)$/i.test( e ) ) {
				return ! 1;
			}
			var c = '';
			if ( n ) {
				switch ( n.constructor ) {
					case Number:
						c = n === 1 / 0 ? '; expires=Fri, 31 Dec 9999 23:59:59 GMT' : '; max-age=' + n;
						break;
					case String:
						c = '; expires=' + n;
						break;
					case Date:
						c = '; expires=' + n.toUTCString();
				}
			}
			return (
				( 'rootDomain' !== r && '.rootDomain' !== r ) ||
					( r =
						( '.rootDomain' === r ? '.' : '' ) +
						document.location.hostname.split( '.' ).slice( -2 ).join( '.' ) ),
				( document.cookie =
					encodeURIComponent( e ) +
					'=' +
					encodeURIComponent( o ) +
					c +
					( r ? '; domain=' + r : '' ) +
					( t ? '; path=' + t : '' ) +
					( i ? '; secure' : '' ) ),
				! 0
			);
		},
	};

	// Implement IAB USP API.
	window.__uspapi = function ( command, version, callback ) {
		// Validate callback.
		if ( typeof callback !== 'function' ) {
			return;
		}

		// Validate the given command.
		if ( command !== 'getUSPData' || version !== 1 ) {
			callback( null, false );
			return;
		}

		// Check for GPC. If set, override any stored cookie.
		if ( navigator.globalPrivacyControl ) {
			callback( { version: 1, uspString: '1YYN' }, true );
			return;
		}

		// Check for cookie.
		var consent = cookieLib.getItem( 'usprivacy' );

		// Invalid cookie.
		if ( null === consent ) {
			callback( null, false );
			return;
		}

		// Everything checks out. Fire the provided callback with the consent data.
		callback( { version: 1, uspString: consent }, true );
	};

	var setDefaultOptInCookie = function () {
		var value = ccpaSettings.defaultOptInCookieString;
		var domain =
			'.wordpress.com' === location.hostname.slice( -14 ) ? '.rootDomain' : location.hostname;
		cookieLib.setItem( 'usprivacy', value, 365 * 24 * 60 * 60, '/', domain );
	};

	var setDefaultOptOutCookie = function () {
		var value = ccpaSettings.defaultOptOutCookieString;
		var domain =
			'.wordpress.com' === location.hostname.slice( -14 ) ? '.rootDomain' : location.hostname;
		cookieLib.setItem( 'usprivacy', value, 24 * 60 * 60, '/', domain );
	};

	var setDefaultNotApplicableCookie = function () {
		var value = '1---';
		var domain =
			'.wordpress.com' === location.hostname.slice( -14 ) ? '.rootDomain' : location.hostname;
		cookieLib.setItem( 'usprivacy', value, 24 * 60 * 60, '/', domain );
	};

	var setCcpaAppliesCookie = function ( value ) {
		var domain =
			'.wordpress.com' === location.hostname.slice( -14 ) ? '.rootDomain' : location.hostname;
		cookieLib.setItem( 'ccpa_applies', value, 24 * 60 * 60, '/', domain );
	};

	var injectLoadingMessage = function () {
		var wrapper = document.createElement( 'div' );
		document.body.insertBefore( wrapper, document.body.firstElementChild );
		wrapper.outerHTML =
			'<div id="ccpa-loading" class="cleanslate ccpa__loading-wrapper">' +
			'<div class="ccpa__loading-overlay">' +
			'<span class="ccpa__loading-message">' +
			ccpaSettings.strings.pleaseWait +
			'...</span>' +
			'</div>' +
			'</div>';
	};

	var destroyModal = function () {
		var node = document.querySelector( '#ccpa-modal' );

		if ( node ) {
			node.parentElement.removeChild( node );
		}
	};

	var injectModal = function () {
		destroyModal();

		injectLoadingMessage();

		var request = new XMLHttpRequest();
		request.open(
			'GET',
			ccpaSettings.ajaxUrl + '?action=privacy_optout_markup&security=' + ccpaSettings.ajaxNonce,
			true
		);
		request.onreadystatechange = function () {
			if ( 4 === this.readyState ) {
				if ( 200 === this.status ) {
					document.getElementById( 'ccpa-loading' ).remove();
					var wrapper = document.createElement( 'div' );
					document.body.insertBefore( wrapper, document.body.firstElementChild );
					wrapper.outerHTML = this.response;
					document.getElementById( 'ccpa-opt-out' ).focus();

					var optOut = document.querySelector( '#ccpa-modal .opt-out' );
					optOut.addEventListener( 'click', function ( e ) {
						var post = new XMLHttpRequest();
						post.open( 'POST', ccpaSettings.ajaxUrl, true );
						post.setRequestHeader(
							'Content-Type',
							'application/x-www-form-urlencoded; charset=UTF-8'
						);
						post.onreadystatechange = function () {
							if ( 4 === this.readyState ) {
								if ( 200 === this.status ) {
									var result = JSON.parse( this.response );

									if ( result && result.success ) {
										// Note: Cooke is set in HTTP response from POST, so only need to update the toggle switch state.
										if ( result.data ) {
											e.target.parentNode.classList.add( 'is-checked' );
											e.target.parentNode.parentNode.classList.add( 'is-checked' );
										} else {
											e.target.parentNode.classList.remove( 'is-checked' );
											e.target.parentNode.parentNode.classList.remove( 'is-checked' );
										}
									}
								}
							}
						};
						post.send(
							'action=privacy_optout&optout=' +
								e.target.checked +
								'&security=' +
								ccpaSettings.ajaxNonce
						);
					} );

					// Set initial toggle status based on cookie data.
					var usprivacyCookie = cookieLib.getItem( 'usprivacy' );
					var optout = usprivacyCookie && 'Y' === usprivacyCookie[ 2 ];
					var toggle = document.querySelector( '#ccpa-modal .opt-out' );

					toggle.checked = optout;

					if ( optout ) {
						toggle.parentNode.classList.add( 'is-checked' );
						toggle.parentNode.parentNode.classList.add( 'is-checked' );
					}

					var buttons = document.querySelectorAll( '#ccpa-modal .components-button' );
					Array.prototype.forEach.call( buttons, function ( el ) {
						el.addEventListener( 'click', function () {
							destroyModal();
						} );
					} );
				}
			}
		};

		request.send();
	};

	var dispatchInitializedEvent = function ( ccpaApplies ) {
		// Dispatches a custom event with data indicating if the CCPA applies or not once it has been determined.
		// Sites can listen for this event and do additional processing, e.g. showing or hiding additional elements.
		var event = document.createEvent( 'CustomEvent' );
		event.initCustomEvent( 'wordads-ccpa-initialized', true, false, { ccpaApplies: ccpaApplies } );
		document.dispatchEvent( event );
	};

	var initialize = function ( ccpaApplies, usprivacyCookie ) {
		// Get any Do Not Sell links on the page.
		var dnsLinks = document.querySelectorAll( '.ccpa-do-not-sell' );

		// No usprivacy cookie, so we need to set it.
		if ( null === usprivacyCookie ) {
			if ( ccpaApplies ) {
				if ( 0 === dnsLinks.length ) {
					// Could not find a Do Not Sell link as required, so default to opt-OUT just to be safe.
					setDefaultOptOutCookie();
				} else {
					// Found a Do Not Sell link, so set default opt-in.
					setDefaultOptInCookie();
				}
			} else {
				// CCPA does not apply.
				setDefaultNotApplicableCookie();
			}
		}

		// If CCPA does not apply, and we are not overriding it for admins, then we can stop here.
		if ( ! ccpaApplies && 'false' === ccpaSettings.forceApplies ) {
			dispatchInitializedEvent( false );
			return;
		}

		// Displays Do Not Sell links and adds handlers to display the modal when clicked.
		Array.prototype.forEach.call( dnsLinks, function ( dnsLink ) {
			dnsLink.addEventListener( 'click', function ( e ) {
				e.preventDefault();

				if ( ! ccpaSettings.stylesLoaded ) {
					// Load wordads-ccpa.min.css.
					var ccpaCss = document.createElement( 'link' );
					ccpaCss.rel = 'stylesheet';
					ccpaCss.type = 'text/css';
					ccpaCss.href = ccpaSettings.ccpaCssUrl;
					document.getElementsByTagName( 'HEAD' )[ 0 ].appendChild( ccpaCss );

					ccpaSettings.stylesLoaded = true;
				}

				injectModal();
			} );

			// Make the link visible.
			dnsLink.style.display = '';
		} );

		// CCPA applies (or we're forcing it to display for admins). Let any listeners know.
		dispatchInitializedEvent( true );
	};

	// Setup CCPA on DOM loaded.
	document.addEventListener( 'DOMContentLoaded', function () {
		// Look for usprivacy cookies first.
		var usprivacyCookie = cookieLib.getItem( 'usprivacy' );

		// Found a usprivacy cookie.
		if ( null !== usprivacyCookie ) {
			// CCPA does not apply.
			if ( '1---' === usprivacyCookie ) {
				initialize( false, usprivacyCookie );
			} else {
				// CCPA applies.
				initialize( true, usprivacyCookie );
			}

			// No more processing needed.
			return;
		}

		// We don't have a usprivacy cookie, so check to see if we have a CCPA applies cookie.
		var ccpaCookie = cookieLib.getItem( 'ccpa_applies' );

		// No CCPA applies cookie found, so we'll need to geolocate if this visitor is from applicable US state.
		// This needs to happen client side because we do not have region geo data in our $SERVER headers,
		// only country data -- therefore we can't vary cache on the region.
		if ( null === ccpaCookie ) {
			var request = new XMLHttpRequest();
			request.open( 'GET', 'https://public-api.wordpress.com/geo/', true );

			request.onreadystatechange = function () {
				if ( 4 === this.readyState ) {
					if ( 200 === this.status ) {
						// Got a geo response. Parse out the region data.
						var data = JSON.parse( this.response );
						var region = data.region ? data.region.toLowerCase() : '';
						var ccpaApplies =
							[
								'california',
								'colorado',
								'connecticut',
								'delaware',
								'indiana',
								'iowa',
								'montana',
								'new jersey',
								'oregon',
								'tennessee',
								'texas',
								'utah',
								'virginia',
							].indexOf( region ) > -1;

						// Set CCPA applies cookie. This keeps us from having to make a geo request too frequently.
						setCcpaAppliesCookie( ccpaApplies );

						// Perform the rest of the initialization.
						initialize( ccpaApplies, null );
					} else {
						// Geolocation request failed, so default to CCPA applies just to be safe.
						setCcpaAppliesCookie( true );

						// Perform the rest of the initialization.
						initialize( true, null );
					}
				}
			};

			// Send the geo request.
			request.send();
		} else {
			// We found a CCPA applies cookie. Continue with initialization.
			initialize( 'true' === ccpaCookie, null );
		}
	} );
} )();
