<?php
/**
 * Class AMP_Template_Customizer
 *
 * @package AMP
 */

use AmpProject\AmpWP\Admin\ReaderThemes;
use AmpProject\AmpWP\Option;
use AmpProject\AmpWP\QueryVar;
use AmpProject\AmpWP\ReaderThemeLoader;
use AmpProject\AmpWP\Services;

/**
 * AMP class that implements a template style editor in the Customizer.
 *
 * A direct, formed link to the AMP editor in the Customizer is added via
 * {@see amp_customizer_editor_link()} as a submenu to the Appearance menu.
 *
 * @since 0.4
 * @internal
 */
class AMP_Template_Customizer {

	/**
	 * AMP template editor panel ID.
	 *
	 * @since 0.4
	 * @var string
	 */
	const PANEL_ID = 'amp_panel';

	/**
	 * Theme mod name to contain timestamps for when theme mods were last modified.
	 *
	 * @since 2.0
	 * @var string
	 */
	const THEME_MOD_TIMESTAMPS_KEY = 'amp_customize_setting_modified_timestamps';

	/**
	 * Customizer instance.
	 *
	 * @since 0.4
	 * @var WP_Customize_Manager $wp_customize
	 */
	protected $wp_customize;

	/**
	 * Reader theme loader.
	 *
	 * @since 2.0
	 * @var ReaderThemeLoader
	 */
	protected $reader_theme_loader;

	/**
	 * AMP_Template_Customizer constructor.
	 *
	 * @param WP_Customize_Manager $wp_customize        Customize manager.
	 * @param ReaderThemeLoader    $reader_theme_loader Reader theme loader instance.
	 */
	protected function __construct( WP_Customize_Manager $wp_customize, ReaderThemeLoader $reader_theme_loader ) {
		$this->wp_customize        = $wp_customize;
		$this->reader_theme_loader = $reader_theme_loader;
	}

	/**
	 * Initialize the template Customizer feature class.
	 *
	 * @static
	 * @since 0.4
	 * @access public
	 *
	 * @param WP_Customize_Manager   $wp_customize        Customizer instance.
	 * @param ReaderThemeLoader|null $reader_theme_loader Reader theme loader.
	 * @return AMP_Template_Customizer Instance.
	 */
	public static function init( WP_Customize_Manager $wp_customize, ReaderThemeLoader $reader_theme_loader = null ) {
		if ( null === $reader_theme_loader ) {
			$reader_theme_loader = Services::get( 'reader_theme_loader' );
		}
		$self = new self( $wp_customize, $reader_theme_loader );

		$is_reader_mode   = ( AMP_Theme_Support::READER_MODE_SLUG === AMP_Options_Manager::get_option( Option::THEME_SUPPORT ) );
		$has_reader_theme = ( ReaderThemes::DEFAULT_READER_THEME !== AMP_Options_Manager::get_option( Option::READER_THEME ) ); // @todo Verify that the theme actually exists.

		if ( $is_reader_mode ) {
			add_action( 'customize_controls_init', [ $self, 'set_reader_preview_url' ] );

			if ( $has_reader_theme ) {
				add_action( 'customize_save_after', [ $self, 'store_modified_theme_mod_setting_timestamps' ] );
			}

			if ( $reader_theme_loader->is_theme_overridden() ) {
				add_action( 'customize_controls_enqueue_scripts', [ $self, 'add_customizer_scripts' ] );
				add_action( 'customize_controls_print_footer_scripts', [ $self, 'render_setting_import_section_template' ] );
			} elseif ( ! $has_reader_theme ) {
				/**
				 * Fires when the AMP Template Customizer initializes.
				 *
				 * In practice the `customize_register` hook should be used instead.
				 *
				 * @param AMP_Template_Customizer $self Instance.
				 *
				 * @since 0.4
				 */
				do_action( 'amp_customizer_init', $self );

				$self->register_legacy_settings();
				$self->register_legacy_ui();

				add_action( 'customize_controls_print_footer_scripts', [ $self, 'print_legacy_controls_templates' ] );
				add_action( 'customize_preview_init', [ $self, 'init_legacy_preview' ] );

				add_action( 'customize_controls_enqueue_scripts', [ $self, 'add_legacy_customizer_scripts' ] );
			}
		}

		$self->set_refresh_setting_transport();
		$self->remove_cover_template_section();
		$self->remove_homepage_settings_section();
		return $self;
	}

	/**
	 * Set the preview URL when using a Reader theme if the AMP preview permalink was requested and no URL was provided.
	 */
	public function set_reader_preview_url() {
		if ( isset( $_GET[ QueryVar::AMP_PREVIEW ] ) && ! isset( $_GET['url'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			$url = amp_admin_get_preview_permalink();
			if ( $url ) {
				$this->wp_customize->set_preview_url( $url );
			}
		}
	}

	/**
	 * Force changes to header video to cause refresh since there are various JS dependencies that prevent selective refresh from working properly.
	 *
	 * In the AMP Customizer preview, selective refresh partial for `custom_header` will render <amp-video> or <amp-youtube> elements.
	 * Nevertheless, custom-header.js in core is not expecting AMP components. Therefore the `wp-custom-header-video-loaded` event never
	 * fires. This prevents themes from toggling the `has-header-video` class on the body.
	 *
	 * Additionally, the Twenty Seventeen core theme (the only which supports header videos) has two separate scripts
	 * `twentyseventeen-global` and `twentyseventeen-skip-link-focus-fix` which are depended on for displaying the
	 * video, for example toggling the 'has-header-video' class when the video is added or removed.
	 *
	 * This applies whenever AMP is being served in the Customizer preview, that is, in Standard mode or Reader mode with a Reader theme.
	 */
	protected function set_refresh_setting_transport() {
		if ( ! amp_is_canonical() && ! $this->reader_theme_loader->is_theme_overridden() ) {
			return;
		}

		$setting_ids = [
			'header_video',
			'external_header_video',
		];
		foreach ( $setting_ids as $setting_id ) {
			$setting = $this->wp_customize->get_setting( $setting_id );
			if ( $setting ) {
				$setting->transport = 'refresh';
			}
		}
	}

	/**
	 * Remove the Cover Template section if needed.
	 *
	 * Prevent showing the "Cover Template" section if the active (non-Reader) theme does not have the same template
	 * as Twenty Twenty, as otherwise the user would be shown a section that would never reflect any preview change.
	 */
	protected function remove_cover_template_section() {
		if ( ! $this->reader_theme_loader->is_theme_overridden() ) {
			return;
		}

		$active_theme = $this->reader_theme_loader->get_active_theme();
		$reader_theme = $this->reader_theme_loader->get_reader_theme();
		if ( ! $active_theme instanceof WP_Theme || ! $reader_theme instanceof WP_Theme ) {
			return;
		}

		// This only applies to Twenty Twenty.
		if ( $reader_theme->get_template() !== 'twentytwenty' ) {
			return;
		}

		// Prevent deactivating the cover template if the active theme and reader theme both have a cover template.
		$cover_template_name = 'templates/template-cover.php';
		if (
			array_key_exists( $cover_template_name, $active_theme->get_page_templates() )
			&&
			array_key_exists( $cover_template_name, $reader_theme->get_page_templates() )
		) {
			return;
		}

		$this->wp_customize->remove_section( 'cover_template_options' );
	}

	/**
	 * Remove the Homepage Settings section in the AMP Customizer for a Reader theme if needed.
	 *
	 * The Homepage Settings section exclusively contains controls for options which apply to both AMP and non-AMP.
	 * If this is the case and there are no other controls added to it, then remove the section. Otherwise, the controls
	 * will all get the same notice added to them.
	 */
	protected function remove_homepage_settings_section() {
		if ( ! $this->reader_theme_loader->is_theme_overridden() ) {
			return;
		}

		$section_id  = 'static_front_page';
		$control_ids = [];
		foreach ( $this->wp_customize->controls() as $control ) {
			/** @var WP_Customize_Control $control */
			if ( $section_id === $control->section ) {
				$control_ids[] = $control->id;
			}
		}

		$static_front_page_control_ids = [
			'show_on_front',
			'page_on_front',
			'page_for_posts',
		];

		if ( count( array_diff( $control_ids, $static_front_page_control_ids ) ) === 0 ) {
			$this->wp_customize->remove_section( $section_id );
		}
	}

	/**
	 * Init Customizer preview for legacy.
	 *
	 * @since 0.4
	 */
	public function init_legacy_preview() {
		// This is only needed in WP<5.7 because in 5.7 the `wp_robots()` function runs at the `amp_post_template_head`
		// action and in `WP_Customize_Manager::customize_preview_init()` the `wp_robots_no_robots()` function is added
		// to the `wp_robots` filter.
		if ( version_compare( strtok( get_bloginfo( 'version' ), '-' ), '5.7', '<' ) ) {
			// There is code coverage for this, but code coverage is only collected for the latest WP version.
			add_action( 'amp_post_template_head', 'wp_no_robots' ); // @codeCoverageIgnore
		}

		add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_legacy_preview_scripts' ] );
		add_action( 'amp_customizer_enqueue_preview_scripts', [ $this, 'enqueue_legacy_preview_scripts' ] );

		// Output scripts and styles which will break AMP validation only when preview is opened with controls for manipulation.
		if ( $this->wp_customize->get_messenger_channel() ) {
			add_action( 'amp_post_template_head', [ $this->wp_customize, 'customize_preview_loading_style' ] );
			add_action( 'amp_post_template_css', [ $this, 'add_legacy_customize_preview_styles' ] );
			add_action( 'amp_post_template_head', [ $this->wp_customize, 'remove_frameless_preview_messenger_channel' ] );
			add_action( 'amp_post_template_footer', [ $this, 'add_legacy_preview_scripts' ] );
		}
	}

	/**
	 * Sets up the AMP Customizer preview.
	 */
	public function register_legacy_ui() {
		$this->wp_customize->add_panel(
			self::PANEL_ID,
			[
				'type'        => 'amp',
				'title'       => __( 'AMP', 'amp' ),
				'description' => $this->get_amp_panel_description(),
			]
		);

		/**
		 * Fires after the AMP panel has been registered for plugins to add additional controls.
		 *
		 * In practice the `customize_register` hook should be used instead.
		 *
		 * @since 0.4
		 * @param WP_Customize_Manager $manager Manager.
		 */
		do_action( 'amp_customizer_register_ui', $this->wp_customize );
	}

	/**
	 * Get AMP panel description.
	 *
	 * This is also added to the root panel description in the AMP Customizer when a Reader theme is being customized.
	 *
	 * @return string Description, with markup.
	 */
	protected function get_amp_panel_description() {
		return wp_kses_post(
			sprintf(
				/* translators: 1: URL to AMP project, 2: URL to admin settings screen */
				__( 'While <a href="%1$s" target="_blank">AMP</a> works well on both desktop and mobile pages, your site is <a href="%2$s" target="_blank">currently configured</a> in Reader mode to serve AMP pages to mobile visitors. These settings customize the experience for these users.', 'amp' ),
				'https://amp.dev',
				admin_url( 'admin.php?page=amp-options' )
			)
		);
	}

	/**
	 * Registers settings for customizing Legacy Reader AMP templates.
	 *
	 * @since 0.4
	 */
	public function register_legacy_settings() {

		/**
		 * Fires when plugins should register settings for AMP.
		 *
		 * In practice the `customize_register` hook should be used instead.
		 *
		 * @since 0.4
		 * @param WP_Customize_Manager $manager Manager.
		 */
		do_action( 'amp_customizer_register_settings', $this->wp_customize );
	}

	/**
	 * Load up AMP scripts needed for Customizer integrations when a Reader theme has been selected.
	 *
	 * @since 2.0
	 */
	public function add_customizer_scripts() {
		$handle       = 'amp-customize-controls';
		$asset_file   = AMP__DIR__ . '/assets/js/amp-customize-controls.asset.php';
		$asset        = require $asset_file;
		$dependencies = $asset['dependencies'];
		$version      = $asset['version'];

		wp_enqueue_script(
			$handle,
			amp_get_asset_url( 'js/amp-customize-controls.js' ),
			array_merge( $dependencies, [ 'jquery', 'customize-controls' ] ),
			$version,
			true
		);
		if ( function_exists( 'wp_set_script_translations' ) ) {
			wp_set_script_translations( $handle, 'amp' );
		} elseif ( function_exists( 'wp_get_jed_locale_data' ) || function_exists( 'gutenberg_get_jed_locale_data' ) ) {
			$locale_data = function_exists( 'wp_get_jed_locale_data' ) ? wp_get_jed_locale_data( 'amp' ) : gutenberg_get_jed_locale_data( 'amp' );
			wp_add_inline_script(
				$handle,
				sprintf( 'wp.i18n.setLocaleData( %s, "amp" );', wp_json_encode( $locale_data ) ),
				'after'
			);
		}

		$option_settings = [];
		foreach ( $this->wp_customize->settings() as $setting ) {
			/** @var WP_Customize_Setting $setting */
			if ( 'option' === $setting->type ) {
				$option_settings[] = $setting->id;
			}
		}

		wp_add_inline_script(
			$handle,
			sprintf(
				'ampCustomizeControls.boot( %s );',
				wp_json_encode(
					[
						'queryVar'                  => amp_get_slug(),
						'optionSettings'            => $option_settings,
						'activeThemeSettingImports' => $this->get_active_theme_import_settings(),
						'mimeTypeIcons'             => [
							'image'    => wp_mime_type_icon( 'image' ),
							'document' => wp_mime_type_icon( 'document' ),
						],
						'l10n'                      => [
							/* translators: placeholder is URL to non-AMP Customizer. */
							'ampVersionNotice'     => wp_kses_post( sprintf( __( 'You are customizing the AMP version of your site. <a href="%s">Customize non-AMP version</a>.', 'amp' ), esc_url( admin_url( 'customize.php' ) ) ) ),
							'rootPanelDescription' => $this->get_amp_panel_description(),
						],
					]
				)
			)
		);

		wp_enqueue_style(
			'amp-customizer',
			amp_get_asset_url( 'css/amp-customizer.css' ),
			[],
			AMP__VERSION
		);

		wp_styles()->add_data( 'amp-customizer', 'rtl', 'replace' );
	}

	/**
	 * Store the timestamps for modified theme settings.
	 *
	 * This is used to determine which settings from the Active theme should be presented for importing into the Reader
	 * theme. If a setting has been modified more recently in the Reader theme, then it doesn't make much sense to offer
	 * for the user to re-import a customization they already made.
	 */
	public function store_modified_theme_mod_setting_timestamps() {
		$modified_setting_ids = [];
		foreach ( array_keys( $this->wp_customize->unsanitized_post_values() ) as $setting_id ) {
			$setting = $this->wp_customize->get_setting( $setting_id );
			if ( ! ( $setting instanceof WP_Customize_Setting ) || $setting instanceof WP_Customize_Filter_Setting ) {
				continue;
			}

			if ( $setting instanceof WP_Customize_Custom_CSS_Setting ) {
				$modified_setting_ids[] = $setting->id_data()['base']; // Remove theme slug from ID.
			} elseif ( 'theme_mod' === $setting->type ) {
				$modified_setting_ids[] = $setting->id;
			}
		}

		if ( empty( $modified_setting_ids ) ) {
			return;
		}

		$theme_mod_timestamps = get_theme_mod( self::THEME_MOD_TIMESTAMPS_KEY, [] );
		foreach ( $modified_setting_ids as $modified_setting_id ) {
			$theme_mod_timestamps[ $modified_setting_id ] = time();
		}
		set_theme_mod( self::THEME_MOD_TIMESTAMPS_KEY, $theme_mod_timestamps );
	}

	/**
	 * Get settings to import from the active theme.
	 *
	 * @return array Map of setting IDs to setting values.
	 */
	protected function get_active_theme_import_settings() {
		$active_theme = $this->reader_theme_loader->get_active_theme();
		if ( ! $active_theme instanceof WP_Theme ) {
			return [];
		}

		$active_theme_mods = get_option( 'theme_mods_' . $active_theme->get_stylesheet(), [] );
		$import_settings   = [];

		$active_setting_timestamps = isset( $active_theme_mods[ self::THEME_MOD_TIMESTAMPS_KEY ] ) ? $active_theme_mods[ self::THEME_MOD_TIMESTAMPS_KEY ] : [];
		$reader_setting_timestamps = get_theme_mod( self::THEME_MOD_TIMESTAMPS_KEY, [] );

		// Remove theme mods which will not be imported directly.
		unset(
			$active_theme_mods['sidebars_widgets'],
			$active_theme_mods['custom_css_post_id'],
			$active_theme_mods['background_preset'], // Since a meta setting. When importing a background setting, will be set to 'custom'.
			$active_theme_mods[ self::THEME_MOD_TIMESTAMPS_KEY ]
		);

		// Avoid offering to import background image settings if no background image is set.
		if ( empty( $active_theme_mods['background_image'] ) ) {
			foreach ( [ 'background_position_x', 'background_position_y', 'background_size', 'background_repeat', 'background_attachment' ] as $setting_id ) {
				unset( $active_theme_mods[ $setting_id ] );
			}
		}

		// Map nav menus for importing.
		if ( isset( $active_theme_mods['nav_menu_locations'] ) ) {
			$nav_menu_locations = wp_map_nav_menu_locations(
				get_theme_mod( 'nav_menu_locations', [] ),
				$active_theme_mods['nav_menu_locations']
			);
			foreach ( $nav_menu_locations as $nav_menu_location => $menu_id ) {
				$setting = $this->wp_customize->get_setting( "nav_menu_locations[$nav_menu_location]" );
				if (
					$setting instanceof WP_Customize_Setting
					&&
					// Skip presenting settings which have been more recently updated in the Reader theme.
					(
						! isset( $active_setting_timestamps[ $setting->id ], $reader_setting_timestamps[ $setting->id ] )
						||
						$active_setting_timestamps[ $setting->id ] > $reader_setting_timestamps[ $setting->id ]
					)
				) {
					/** This filter is documented in wp-includes/class-wp-customize-manager.php */
					$value = apply_filters( "customize_sanitize_js_{$setting->id}", $menu_id, $setting );

					$import_settings[ $setting->id ] = $value;
				}
			}
			unset( $active_theme_mods['nav_menu_locations'] );
		}

		foreach ( $this->wp_customize->settings() as $setting ) {
			/** @var WP_Customize_Setting $setting */
			if (
				'theme_mod' !== $setting->type
				||
				// Skip presenting settings which have been more recently updated in the Reader theme.
				(
					isset( $active_setting_timestamps[ $setting->id ], $reader_setting_timestamps[ $setting->id ] )
					&&
					$reader_setting_timestamps[ $setting->id ] > $active_setting_timestamps[ $setting->id ]
				)
			) {
				continue;
			}

			$id_data = $setting->id_data();
			if ( ! array_key_exists( $id_data['base'], $active_theme_mods ) ) {
				continue;
			}
			$value   = $active_theme_mods[ $id_data['base'] ];
			$subkeys = $id_data['keys'];
			while ( ! empty( $subkeys ) ) {
				$subkey = array_shift( $subkeys );
				if ( ! is_array( $value ) || ! array_key_exists( $subkey, $value ) ) {
					// Move on to the next setting.
					continue 2;
				}
				$value = $value[ $subkey ];
			}

			/** This filter is documented in wp-includes/class-wp-customize-manager.php */
			$value = apply_filters( "customize_sanitize_js_{$setting->id}", $value, $setting );

			$import_settings[ $setting->id ] = $value;
		}

		// Import Custom CSS if it has not been more recently updated in the Reader theme.
		if (
			! isset( $active_setting_timestamps['custom_css'], $reader_setting_timestamps['custom_css'] )
			||
			$active_setting_timestamps['custom_css'] > $reader_setting_timestamps['custom_css']
		) {
			$custom_css_setting = $this->wp_customize->get_setting( sprintf( 'custom_css[%s]', get_stylesheet() ) );
			$custom_css_post    = wp_get_custom_css_post( $active_theme->get_stylesheet() );
			if ( $custom_css_setting instanceof WP_Customize_Custom_CSS_Setting && $custom_css_post instanceof WP_Post ) {
				$value = $custom_css_post->post_content;

				/** This filter is documented in wp-includes/class-wp-customize-setting.php */
				$value = apply_filters( 'customize_value_custom_css', $value, $custom_css_setting );

				/** This filter is documented in wp-includes/class-wp-customize-manager.php */
				$value = apply_filters( "customize_sanitize_js_{$custom_css_setting->id}", $value, $custom_css_setting );

				$import_settings[ $custom_css_setting->id ] = $value;
			}
		}

		return $import_settings;
	}

	/**
	 * Render template for the setting import "section".
	 *
	 * This section only has a menu item and it is not intended to expand.
	 */
	public function render_setting_import_section_template() {
		?>
		<script type="text/html" id="tmpl-customize-section-amp_active_theme_settings_import">
			<li id="accordion-section-{{ data.id }}" class="accordion-section control-section control-section-{{ data.type }}">
				<h3 class="accordion-section-title">
					<button type="button" class="button button-secondary" aria-label="<?php esc_attr_e( 'Import settings', 'amp' ); ?>">
						<?php echo esc_html( _x( 'Import', 'theme', 'amp' ) ); ?>
					</button>
					<details>
						<summary>{{ data.title }}</summary>
						<div>
							<p>
								<?php esc_html_e( 'You can import some settings from the primary Active theme into the corresponding Reader theme settings.', 'amp' ); ?>
							</p>
							<dl></dl>
						</div>
					</details>
				</h3>
				<ul class="accordion-section-content"></ul>
			</li>
		</script>
		<?php
	}

	/**
	 * Load up AMP scripts needed for Customizer integrations in Legacy Reader mode.
	 *
	 * @since 0.6 Originally called add_customizer_scripts.
	 * @since 2.0
	 */
	public function add_legacy_customizer_scripts() {
		$asset_file   = AMP__DIR__ . '/assets/js/amp-customize-controls-legacy.asset.php';
		$asset        = require $asset_file;
		$dependencies = $asset['dependencies'];
		$version      = $asset['version'];

		wp_enqueue_script(
			'amp-customize-controls', // Note: This is not 'amp-customize-controls-legacy' to not break existing scripts that have this dependency.
			amp_get_asset_url( 'js/amp-customize-controls-legacy.js' ),
			array_merge( $dependencies, [ 'jquery', 'customize-controls' ] ),
			$version,
			true
		);

		wp_add_inline_script(
			'amp-customize-controls',
			sprintf(
				'ampCustomizeControls.boot( %s );',
				wp_json_encode(
					[
						'queryVar' => amp_get_slug(),
						'panelId'  => self::PANEL_ID,
						'ampUrl'   => amp_admin_get_preview_permalink(),
						'l10n'     => [
							'unavailableMessage'  => __( 'AMP is not available for the page currently being previewed.', 'amp' ),
							'unavailableLinkText' => __( 'Navigate to an AMP compatible page', 'amp' ),
						],
					]
				)
			)
		);

		wp_enqueue_style(
			'amp-customizer',
			amp_get_asset_url( 'css/amp-customizer-legacy.css' ),
			[],
			AMP__VERSION
		);

		wp_styles()->add_data( 'amp-customizer', 'rtl', 'replace' );

		/**
		 * Fires when plugins should register settings for AMP.
		 *
		 * In practice the `customize_controls_enqueue_scripts` hook should be used instead.
		 *
		 * @since 0.4
		 * @param WP_Customize_Manager $manager Manager.
		 */
		do_action( 'amp_customizer_enqueue_scripts', $this->wp_customize );
	}

	/**
	 * Enqueues scripts used in both the AMP and non-AMP Customizer preview (only applies to Legacy Reader mode).
	 *
	 * @since 0.6
	 */
	public function enqueue_legacy_preview_scripts() {
		// Bail if user can't customize anyway.
		if ( ! current_user_can( 'customize' ) ) {
			return;
		}

		$asset_file   = AMP__DIR__ . '/assets/js/amp-customize-preview-legacy.asset.php';
		$asset        = require $asset_file;
		$dependencies = $asset['dependencies'];
		$version      = $asset['version'];

		wp_enqueue_script(
			'amp-customize-preview',
			amp_get_asset_url( 'js/amp-customize-preview-legacy.js' ),
			array_merge( $dependencies, [ 'jquery', 'customize-preview' ] ),
			$version,
			true
		);

		wp_add_inline_script(
			'amp-customize-preview',
			sprintf(
				'ampCustomizePreview.boot( %s );',
				wp_json_encode(
					[
						'available' => amp_is_available(),
						'enabled'   => amp_is_request(),
					]
				)
			)
		);
	}

	/**
	 * Add AMP Customizer preview styles for Legacy Reader mode.
	 */
	public function add_legacy_customize_preview_styles() {
		?>
		/* Text meant only for screen readers; this is needed for wp.a11y.speak() */
		.screen-reader-text {
			border: 0;
			clip: rect(1px, 1px, 1px, 1px);
			-webkit-clip-path: inset(50%);
			clip-path: inset(50%);
			height: 1px;
			margin: -1px;
			overflow: hidden;
			padding: 0;
			position: absolute;
			width: 1px;
			word-wrap: normal !important;
		}
		body.wp-customizer-unloading {
			opacity: 0.25 !important; /* Because AMP sets body to opacity:1 once layout complete. */
		}
		<?php
	}

	/**
	 * Enqueues Legacy Reader scripts and does wp_print_footer_scripts() so we can output customizer scripts.
	 *
	 * This breaks AMP validation in the customizer but is necessary for the live preview.
	 *
	 * @since 0.6
	 */
	public function add_legacy_preview_scripts() {

		// Bail if user can't customize anyway.
		if ( ! current_user_can( 'customize' ) ) {
			return;
		}

		wp_enqueue_script( 'customize-selective-refresh' );

		/**
		 * Fires when plugins should enqueue their own scripts for the AMP Customizer preview.
		 *
		 * @since 0.4
		 * @param WP_Customize_Manager $wp_customize Manager.
		 */
		do_action( 'amp_customizer_enqueue_preview_scripts', $this->wp_customize );

		$this->wp_customize->customize_preview_settings();
		$this->wp_customize->selective_refresh->export_preview_data();

		wp_print_footer_scripts();
	}

	/**
	 * Print templates needed for AMP in Customizer (for Legacy Reader mode).
	 *
	 * @since 0.6
	 */
	public function print_legacy_controls_templates() {
		?>
		<script type="text/html" id="tmpl-customize-amp-enabled-toggle">
			<div class="amp-toggle">
				<# var elementIdPrefix = _.uniqueId( 'customize-amp-enabled-toggle' ); #>
				<div id="{{ elementIdPrefix }}tooltip" aria-hidden="true" class="tooltip" role="tooltip">
					{{ data.message }}
					<# if ( data.url ) { #>
						<a href="{{ data.url }}">{{ data.linkText }}</a>
					<# } #>
				</div>
				<input id="{{ elementIdPrefix }}checkbox" type="checkbox" class="disabled" aria-describedby="{{ elementIdPrefix }}tooltip">
				<span class="slider"></span>
				<label for="{{ elementIdPrefix }}checkbox" class="screen-reader-text"><?php esc_html_e( 'AMP preview enabled', 'amp' ); ?></label>
			</div>
		</script>
		<script type="text/html" id="tmpl-customize-amp-unavailable-notification">
			<li class="notice notice-{{ data.type || 'info' }} {{ data.alt ? 'notice-alt' : '' }} {{ data.containerClasses || '' }}" data-code="{{ data.code }}" data-type="{{ data.type }}">
				<div class="notification-message">
					{{ data.message }}
					<# if ( data.url ) { #>
						<a href="{{ data.url }}">{{ data.linkText }}</a>
					<# } #>
				</div>
			</li>
		</script>
		<?php
	}

	/**
	 * Whether the Customizer is AMP. This is always true since the AMP Customizer has been merged with the main Customizer.
	 *
	 * @codeCoverageIgnore
	 * @deprecated 0.6
	 * @return bool
	 */
	public static function is_amp_customizer() {
		_deprecated_function( __METHOD__, '0.6' );
		return true;
	}
}
