/**
 * External dependencies
 */
import React, { useEffect, useState, useRef } from 'react';

/**
 * WordPress dependencies
 */
const { __ } = wp.i18n;
import { dispatch, useSelect } from '@wordpress/data';

/**
 * Internal dependencies
 */
import { STORE_NAME } from '../../data/minify';
import './summary.scss';
import Tooltip from '../../components/sui-tooltip';
import Icon from '../../components/sui-icon';
import List from '../../components/sui-list';
import BoxSummary from '../../components/sui-box-summary';
import Tag from '../../components/sui-tag';
import Toggle from '../../components/sui-toggle';
import Button from '../../components/sui-button';
import HBAPIFetch from '../../api';
import useSummaryUpdate from './utils/summaryUpdate';
import { toggleCDNHelper } from '../../../js/utils/helpers';

/**
 * MinifySummary functional component.
 *
 * @since 3.4.0
 * @param {Object} props
 * @return {JSX.Element} Summary meta box
 */
export const MinifySummary = ( props ) => {
	const summaryUpdate = useSummaryUpdate();
	const didMount = useRef( false );
	const aoQueueRef = useRef( null );
	const api = new HBAPIFetch();
	const [ loading, setLoading ] = useState( true );
	const { cdn, safeMode, assets, hasResolved, delayJs, criticalCss, aoQueue } = useSelect( ( select ) => {
		if ( ! select( STORE_NAME ).hasStartedResolution( 'getOptions' ) ) {
			select( STORE_NAME ).getOptions();
		}

		return {
			cdn: select( STORE_NAME ).getOption( 'cdn' ),
			safeMode: select( STORE_NAME ).getOption( 'safeMode' ),
			assets: select( STORE_NAME ).getAssets(),
			hasResolved: select( STORE_NAME ).hasFinishedResolution( 'getOptions' ) && select( STORE_NAME ).hasFinishedResolution( 'getAssets' ),
			delayJs: select( STORE_NAME ).getOption( 'delay_js' ),
			criticalCss: select( STORE_NAME ).getOption( 'critical_css' ),
			aoQueue: select( STORE_NAME ).getOption( 'ao_queue' ),

		};
	}, [] );

	/**
	 * Sync loading state with resolver.
	 *
	 * @since 3.4.0
	 */
	useEffect( () => {
		if ( loading && hasResolved ) {
			setTimeout( () => {
				setLoading( false );
			}, 250 );
		}
	}, [ hasResolved, setLoading ] );

	useEffect( () => {
		if ( didMount.current ) {
			const viewDelayJs = document.getElementById( 'view_delay_js' );
			if ( viewDelayJs ) {
				if ( viewDelayJs.disabled ) {
					viewDelayJs.disabled = false;
				} else if ( viewDelayJs.checked !== delayJs ) {
					viewDelayJs.checked = delayJs;
					jQuery( viewDelayJs ).trigger( 'change' );
				}
			}

			const viewCriticalCss = document.getElementById( 'critical_css_toggle' );
			if ( viewCriticalCss ) {
				if ( viewCriticalCss.checked !== criticalCss ) {
					viewCriticalCss.checked = criticalCss;
					jQuery( viewCriticalCss ).trigger( 'change' );
				}
			}
		} else {
			didMount.current = true;
		}
	}, [ delayJs, criticalCss ] );

	useEffect( () => {
		const preValue = aoQueueRef.current;
		aoQueueRef.current = aoQueue;
		if ( preValue?.aoQueueCount > 0 && aoQueueRef?.current?.aoQueueCount <= 0 ) {
			dispatch( STORE_NAME ).invalidateResolution( 'getAssets' );
		}
	}, [ aoQueue ] );

	useEffect( () => {
		const intervalAOQueue = setInterval( () => {
			const currentAoQueue = aoQueueRef.current;
			if ( currentAoQueue?.aoQueueCount > 0 ) {
				dispatch( STORE_NAME ).invalidateResolution( 'getOptions' );
			} else {
				clearInterval( intervalAOQueue );
			}
		}, 15000 );
		// Cleanup function to clear the interval when the component unmounts or the dependencies change
		return () => clearInterval( intervalAOQueue );
	}, [ loading ] );

	/**
	 * Get original/compressed sizes.
	 *
	 * @since 3.4.0
	 *
	 * @return {Array} Array of original and compressed sizes.
	 */
	const getSizes = () => {
		if ( undefined === assets.styles || undefined === assets.scripts ) {
			return [ 0, 0, 0 ];
		}
		if ( undefined === assets.dashboard_data || undefined === assets.dashboard_data.original_size || undefined === assets.dashboard_data.compressed_size || undefined === assets.dashboard_data.percentage ) {
			return [ 0, 0, 0 ];
		}

		return [ assets.dashboard_data.original_size, assets.dashboard_data.compressed_size, assets.dashboard_data.percentage ];
	};

	/**
	 * Get compressed size stats.
	 *
	 * @since 3.4.0
	 *
	 * @return {number} Compressed size value.
	 */
	const getCompressedSize = () => {
		const sizes = getSizes();
		return sizes[ 1 ];
	};

	/**
	 * Get number of enqueued files.
	 *
	 * @since 3.4.0
	 *
	 * @return {number} Number of assets
	 */
	const getEnqueuedFiles = () => {
		if ( undefined === assets.styles || undefined === assets.scripts ) {
			return 0;
		}

		let total = Object.keys( assets.styles ).length + Object.keys( assets.scripts ).length;

		if ( undefined !== assets.fonts ) {
			total += Object.keys( assets.fonts ).length;
		}

		return total;
	};

	/**
	 * Get percent optimized value.
	 *
	 * @since 3.4.0
	 *
	 * @return {number} Percent
	 */
	const getPercentOptimized = () => {
		const [ originalSize, compressedSize, percent ] = getSizes();

		if ( 0 === originalSize || 0 === compressedSize || 0 === percent ) {
			return 0;
		}

		return percent;
	};

	/**
	 * Toggle CDN.
	 *
	 * @since 3.4.0
	 *
	 * @param {Object} e
	 */
	const toggleCDN = ( e ) => {
		const checked = e.target.checked;

		toggleCDNHelper( checked, true );

		// Keep legacy setting checkbox in sync.
		const setting = document.getElementById( 'use_cdn_setting' );
		if ( setting ) {
			setting.checked = checked;
		}

		setTimeout( () => {
			dispatch( STORE_NAME ).invalidateResolution( 'getOptions' );
		}, 250 );
	};

	/**
	 * Toggle Delay Js.
	 *
	 * @since 3.4.4
	 *
	 * @param {Object} e
	 */
	const toggleDelay = ( e ) => {
		api.post( 'minify_toggle_delay_js', e.target.checked )
			.then( ( response ) => {
				window.wphbMixPanel.trackDelayJSEvent( {
					update_type: ( response.delay_js ) ? 'activate' : 'deactivate',
					Location: 'ao_summary',
					Timeout: response.delay_js_timeout,
					'Excluded Files': ( response.delay_js_exclude ) ? 'yes' : 'no',
				} );

				dispatch( STORE_NAME ).invalidateResolution( 'getOptions' );
			} )
			.catch( window.console.log );
	};

	/**
	 * Toggle Critical CSS.
	 *
	 * @since 3.6.0
	 *
	 * @param {Object} e
	 */
	const toggleCritical = ( e ) => {
		api.post( 'minify_toggle_critical_css', e.target.checked )
			.then( ( response ) => {
				window.wphbMixPanel.trackCriticalCSSEvent( {
					update_type: response.criticalCss,
					Location: 'ao_summary',
					mode: response.mode,
					settings_modified: '',
					settings_default: '',
				} );

				dispatch( STORE_NAME ).invalidateResolution( 'getOptions' );
				if ( 'activate' === response.criticalCss ) {
					WPHB_Admin.notices.show( wphb.strings.enableCriticalCss, 'blue', false );
					WPHB_Admin.minification.triggerCriticalStatusUpdateAjax( response.htmlForStatusTag );
				} else if ( 'deactivate' === response.criticalCss ) {
					WPHB_Admin.minification.criticalUpdateStatusTag( response.htmlForStatusTag );
				}

				const styleType = 'activate' === response.criticalCss ? 'block' : 'deactivate' === response.criticalCss ? 'none' : '';
				WPHB_Admin.minification.hbToggleElement( 'wphb-clear-critical-css', styleType );
			} )
			.catch( window.console.log );
	};

	/**
	 * Get summary segment content.
	 *
	 * @param  aoQueue
	 * @return {JSX.Element} Summary segment
	 */
	const getSummarySegmentLeft = ( aoQueue ) => {
		const percentage = getPercentOptimized();

		return (
			<div className="sui-summary-details">
				{ 0 === percentage && 'basic' === props.wphbData.mode &&
					<Tooltip text={ __( 'All assets are auto-compressed', 'wphb' ) }>
						<Icon classes="sui-icon-check-tick sui-lg sui-success" />
					</Tooltip> }

				{ 0 === percentage && 'basic' !== props.wphbData.mode && String.fromCharCode( 8212 ) }

				{ 0 !== percentage &&
					<span className="sui-summary-large">
						{ percentage }%
					</span> }
				<span className="sui-summary-sub" style={ { marginBottom: 20 } }> { __( 'Compression savings', 'wphb' ) } </span>
				<span classes={ [ 'sui-summary-detail wphb-summary-detail-total-files' ] }>
					{ __( 'Total Files', 'wphb' ) }
					{ aoQueue?.aoQueueCount ? (
						<Tooltip text={ __( 'Optimizing assets, this could take a while, please hold on.', 'wphb' ) } classes={ [ 'wphb_progress_tag sui-tag sui-tag-blue sui-tooltip-constrained' ] }>
							<span className={ [ 'sui-icon-loader sui-loading' ] } aria-hidden="true"></span>
							{ __( 'Optimizing', 'wphb' ) }
						</Tooltip>
					) : aoQueue?.aoCompletedTime ? (
						<Tooltip
							text={ __( 'Last Generated:', 'wphb' ) + ( aoQueue.aoCompletedTime ? ` ${ aoQueue.aoCompletedTime }` : '' ) }
							classes={ [ 'wphb_progress_tag sui-tag sui-tag-green sui-tooltip-constrained' ] }
						>
							<span className="sui-icon-info" aria-hidden="true"></span>
							{ __( 'Optimized', 'wphb' ) }
						</Tooltip>
					) : null
					}
				</span>
				<span className="sui-summary-sub">{ getEnqueuedFiles() }</span>
			</div>
		);
	};

	/**
	 * Returns unlock pro upsell link.
	 *
	 * @param {string}          utm
	 * @param {string}          eventname
	 * @param {Function | null} actionCall Action call on click. Optional. trackMPEvent used if not provided.
	 * @param {string}          tooltip    Tooltip text. Optional.
	 * @return {JSX.Element} Upsell link
	 */
	const getUnlockUpsellLink = ( utm, eventname, actionCall = null, tooltip = null ) => {
		const linkElement = (
			<a target="_blank" data-location="ao_summary" data-eventname={ eventname } href={ utm } className="wphb-upsell-link wphb-upsell-eo" onClick={ actionCall ? actionCall : trackMPEvent } rel="noreferrer">
				{ __( 'Unlock now', 'wphb' ) + '  ' }
				<span className="sui-icon-open-new-window" aria-hidden="true"></span>
			</a>
		);

		if ( tooltip ) {
			return (
				<Tooltip text={ tooltip } classes={ [ 'sui-tooltip-top-right', 'sui-tooltip-constrained' ] }>
					{ linkElement }
				</Tooltip>
			);
		}

		return linkElement;
	};

	/**
	 * Track EO event on AO summary box.
	 *
	 * @since 3.7.0
	 *
	 * @param {Object} e
	 */
	const trackMPEvent = ( e ) => {
		WPHB_Admin.minification.hbTrackEoMPEvent( e.target );

		return false;
	};

	/**
	 * Get summary segment content.
	 *
	 * @return {JSX.Element} Summary segment
	 */
	const getSummarySegmentRight = () => {
		const compressedSize = getCompressedSize();
		let reduction = compressedSize.toString() + 'kb';

		if ( 'basic' === props.wphbData.mode && 0 === compressedSize ) {
			reduction = (
				<React.Fragment>
					{ __( 'Files are compressed', 'wphb' ) }
					<Icon classes="sui-icon-check-tick sui-md sui-success" />
				</React.Fragment>
			);
		}

		let cdnDetails;
		if ( ! props.wphbData.isMultisite ) {
			if ( props.wphbData.isMember ) {
				cdnDetails =
					<Tooltip text={ __( 'Enable WPMU DEV CDN', 'wphb' ) } classes={ [ 'sui-tooltip-top-right' ] }>
						<Toggle name="use_cdn_summary" id="use_cdn_summary" checked={ cdn && props.wphbData.isMember } disabled={ ! props.wphbData.isMember } onChange={ toggleCDN } />
					</Tooltip>;
			} else {
				cdnDetails = getUnlockUpsellLink( props.wphbData.links.cdnUpsell, 'hb_cdn_upsell', trackCDNUpsell );
			}
		} else if ( cdn && props.wphbData.isMember ) {
			cdnDetails =
				<Tooltip text={ __( 'The Network Admin has the WPMU DEV CDN turned on', 'wphb' ) } classes={ [ 'sui-tooltip-top-right' ] }>
					<Icon classes="sui-icon-check-tick sui-md sui-info" />
				</Tooltip>;
		} else {
			cdnDetails =
				<Tooltip text={ __( 'The Network Admin has the WPMU DEV CDN turned off', 'wphb' ) } classes={ [ 'sui-tooltip-top-right' ] }>
					<Tag value={ __( 'Disabled', 'wphb' ) } type="disabled" />
				</Tooltip>;
		}

		let delayDetails;

		if ( props.wphbData.isMember ) {
			delayDetails =
				<Tooltip text={ __( 'Delay JavaScript Execution', 'wphb' ) } classes={ [ 'sui-tooltip-top-right' ] }>
					<Toggle id="delay_js" checked={ delayJs } onChange={ toggleDelay } />
				</Tooltip>;
		} else {
			delayDetails = getUnlockUpsellLink( props.wphbData.links.delayUpsell, 'delayjs', null );
		}

		let criticalCssDetails;

		if ( props.wphbData.isMember ) {
			criticalCssDetails =
				<Tooltip text={ __( 'Generate Critical CSS', 'wphb' ) } classes={ [ 'sui-tooltip-top-right' ] }>
					<Toggle id="critical_css" checked={ criticalCss } onChange={ toggleCritical } />
				</Tooltip>;
		} else {
			criticalCssDetails = getUnlockUpsellLink( props.wphbData.links.criticalUpsell, 'critical_css', null );
		}

		let elements = [
			{
				label: __( 'Filesize reductions', 'wphb' ),
				details: reduction,
			},
			{
				label: <React.Fragment>
					{ __( 'WPMU DEV CDN', 'wphb' ) }
					{ ! props.wphbData.isMember && <Tooltip classes="sui-tooltip-top-right sui-tooltip-constrained" text={ __( 'Boost your speed globally. Serve your files from our optimized network for maximum performance.' ) }>
						<Icon classes="sui-icon-info sui-md" />
					</Tooltip> }
				</React.Fragment>,
				details: cdnDetails,
			},
		];

		if ( props.wphbData.isMember || ! props.wphbData.links.isEoPage ) {
			const eoElements = [
				{
					label: <React.Fragment>
						{ __( 'Delay JavaScript Execution', 'wphb' ) }
						{ ! props.wphbData.isMember && <Tooltip classes="sui-tooltip-top-right sui-tooltip-constrained" text={ __( 'Unlock immediate speed. Visible content loads first, so your site feels faster.' ) }>
							<Icon classes="sui-icon-info sui-md" />
						</Tooltip> }
					</React.Fragment>,
					details: delayDetails,
				},
				{
					label: <React.Fragment>
						{ __( 'Generate Critical CSS', 'wphb' ) }
						{ ! props.wphbData.isMember && <Tooltip classes="sui-tooltip-top-right sui-tooltip-constrained" text={ __( 'Instantly visible pages. Prioritize essential CSS above the fold for no lag.' ) }>
							<Icon classes="sui-icon-info sui-md" />
						</Tooltip> }
					</React.Fragment>,
					details: criticalCssDetails,
				},
			];

			elements = [ ...elements, ...eoElements ];
		}

		return <List elements={ elements } />;
	};

	/**
	 * Track CDN upsell.
	 *
	 * @since 3.11.0
	 *
	 * @param {Object} element
	 */
	const trackCDNUpsell = ( element ) => {
		window.wphbMixPanel.trackHBUpsell( 'cdn', 'ao_summary', 'cta_clicked', element.target.href, 'hb_cdn_upsell' );
	};

	if ( ! loading ) {
		return (
			<BoxSummary
				loading={ loading || ! hasResolved }
				brandingHeroImage={ props.wphbData.brandingHeroImage }
				hideBranding={ Boolean( props.wphbData.hideBranding ) }
				summarySegmentLeft={ getSummarySegmentLeft( aoQueue ) }
				summarySegmentRight={ getSummarySegmentRight() }
			/>
		);
	}
	return null;
};
