import config from '@automattic/calypso-config';
import { Button, Dialog, FormLabel, Gridicon } from '@automattic/components';
import { addQueryArgs } from '@wordpress/url';
import clsx from 'clsx';
import i18n, { localize } from 'i18n-calypso';
import PropTypes from 'prop-types';
import { createRef, Component, Fragment } from 'react';
import ReactDOM from 'react-dom';
import { connect } from 'react-redux';
import localStorageHelper from 'store';
import QueryUserSettings from 'calypso/components/data/query-user-settings';
import FormInputCheckbox from 'calypso/components/forms/form-checkbox';
import FormTextInput from 'calypso/components/forms/form-text-input';
import { bumpStat } from 'calypso/lib/analytics/mc';
import {
	getLanguageEmpathyModeActive,
	toggleLanguageEmpathyMode,
} from 'calypso/lib/i18n-utils/empathy-mode';
import { TranslationScanner } from 'calypso/lib/i18n-utils/translation-scanner';
import translator, { trackTranslatorStatus } from 'calypso/lib/translator-jumpstart';
import { getCurrentUser } from 'calypso/state/current-user/selectors';
import getCurrentLocaleSlug from 'calypso/state/selectors/get-current-locale-slug';
import getOriginalUserSetting from 'calypso/state/selectors/get-original-user-setting';
import getUserSettings from 'calypso/state/selectors/get-user-settings';
import { setLocale } from 'calypso/state/ui/language/actions';
import './style.scss';

class TranslatorLauncher extends Component {
	static propTypes = {
		translate: PropTypes.func,
	};

	static translationScanner =
		config.isEnabled( 'i18n/translation-scanner' ) && new TranslationScanner();

	static getDerivedStateFromProps( nextProps, prevState ) {
		translator.init( nextProps.currentUser, nextProps.isUserSettingsReady );
		trackTranslatorStatus( nextProps.isTranslatorEnabled );

		if ( prevState.isEnabled !== translator.isEnabled() ) {
			return { ...prevState, isEnabled: translator.isEnabled() };
		}

		return null;
	}

	state = {
		infoDialogVisible: false,
		firstActivation: true,
		isActive: translator.isActivated(),
		isEnabled: translator.isEnabled(),
		isDeliverableHighlightEnabled: false,
		deliverableTarget: null,
		selectedDeliverableTarget: null,
		deliverableTitle: '',
		scrollTop: 0,
	};

	highlightRef = createRef();

	componentDidMount() {
		this.i18nUnsubscribe = i18n.subscribe( this.onI18nChange );
		window.addEventListener( 'keydown', this.handleKeyDown );
	}

	componentWillUnmount() {
		this.i18nUnsubscribe();
		window.removeEventListener( 'keydown', this.handleKeyDown );
	}

	getOriginalIds = () => {
		const { selectedDeliverableTarget } = this.state;

		return [ selectedDeliverableTarget ]
			.concat(
				Array.from( selectedDeliverableTarget.querySelectorAll( '[class*=translator-original-]' ) )
			)
			.reduce( ( ids, node ) => {
				const [ , originalId ] =
					( node.className && node.className.match( /translator-original-(\d+)/ ) ) || [];

				if ( originalId && ids.indexOf( originalId ) === -1 ) {
					ids.push( originalId );
				}

				return ids;
			}, [] );
	};

	getCreateDeliverableUrl = () => {
		const DELIVERABLES_ENDPOINT = 'https://translate.wordpress.com/deliverables/create';
		const { deliverableTitle } = this.state;

		return addQueryArgs( DELIVERABLES_ENDPOINT, {
			original_ids: this.getOriginalIds().join( ',' ),
			title: deliverableTitle,
		} );
	};

	onI18nChange = () => {
		if ( ! this.state.isActive && translator.isActivated() ) {
			// Activating
			this.setState( { isActive: true } );

			if ( ! localStorageHelper.get( 'translator_hide_infodialog' ) ) {
				this.setState( { infoDialogVisible: true } );
			}

			if ( this.state.firstActivation ) {
				bumpStat( 'calypso_translator_toggle', 'intial_activation' );
				this.setState( { firstActivation: false } );
			}
		} else if ( this.state.isActive && ! translator.isActivated() ) {
			// Deactivating
			this.setState( { isActive: false } );
		}
	};

	handleKeyDown = ( event ) => {
		const { isActive, selectedDeliverableTarget } = this.state;

		if ( ! isActive || ! event.getModifierState( 'Control' ) || event.key.toLowerCase() !== 'd' ) {
			return;
		}

		if ( selectedDeliverableTarget ) {
			this.toggleSelectedDeliverableTarget();
		}

		this.toggleDeliverableHighlight();
	};

	handleWindowScroll = () => {
		this.setState( { scrollTop: window.scrollY } );
	};

	handleHighlightMouseMove = ( event ) => {
		const { deliverableTarget } = this.state;

		if ( deliverableTarget !== event.target ) {
			this.setState( { deliverableTarget: event.target } );
		}
	};

	handleHighlightMouseDown = ( event ) => {
		event.preventDefault();
		event.stopPropagation();

		if ( this.highlightRef.current ) {
			this.highlightRef.current.style.pointerEvents = 'all';
		}
	};

	handleHighlightClick = ( event ) => {
		event.preventDefault();
		event.stopPropagation();

		if ( this.highlightRef.current ) {
			this.highlightRef.current.style.pointerEvents = '';
		}

		this.toggleSelectedDeliverableTarget();
		this.toggleDeliverableHighlight();
	};

	handleDeliverableTitleChange = ( event ) => {
		this.setState( { deliverableTitle: event.target.value } );
	};

	handleDeliverableLinkClick = () => {
		this.toggleSelectedDeliverableTarget();
	};

	handleDeliverableCancelClick = () => {
		this.toggleSelectedDeliverableTarget();
	};

	handleDeliverableSubmit = ( event ) => {
		event.preventDefault();

		window.open( this.getCreateDeliverableUrl(), '_blank' );
		this.toggleSelectedDeliverableTarget();
	};

	toggleInfoCheckbox = ( event ) => {
		localStorageHelper.set( 'translator_hide_infodialog', event.target.checked );
	};

	infoDialogClose = () => {
		this.setState( { infoDialogVisible: false } );
	};

	toggleEmpathyMode = () => {
		toggleLanguageEmpathyMode();
	};

	toggle = ( event ) => {
		event.preventDefault();

		const { isEmpathyModeEnabled } = this.props;

		if ( isEmpathyModeEnabled ) {
			this.toggleEmpathyMode();
			return;
		}

		const nextIsActive = translator.toggle();
		bumpStat( 'calypso_translator_toggle', nextIsActive ? 'on' : 'off' );
		this.setState( { isActive: nextIsActive } );
	};

	toggleDeliverableHighlight = () => {
		const isDeliverableHighlightEnabled = ! this.state.isDeliverableHighlightEnabled;

		this.setState( { isDeliverableHighlightEnabled, deliverableTarget: null } );

		if ( isDeliverableHighlightEnabled ) {
			window.addEventListener( 'scroll', this.handleWindowScroll );
			window.addEventListener( 'mousemove', this.handleHighlightMouseMove );
			window.addEventListener( 'mousedown', this.handleHighlightMouseDown );
			window.addEventListener( 'click', this.handleHighlightClick );
		} else {
			window.removeEventListener( 'mousemove', this.handleHighlightMouseMove );
			window.removeEventListener( 'mousedown', this.handleHighlightMouseDown );
			window.removeEventListener( 'click', this.handleHighlightClick );
		}
	};

	toggleSelectedDeliverableTarget = () => {
		this.setState(
			( { deliverableTarget, selectedDeliverableTarget } ) => ( {
				selectedDeliverableTarget: selectedDeliverableTarget ? null : deliverableTarget,
				deliverableTitle: '',
			} ),
			() => {
				const hasSelectedDeliverableTarget = !! this.state.selectedDeliverableTarget;

				document.body.classList.toggle(
					'has-deliverable-highlighted',
					hasSelectedDeliverableTarget
				);

				if ( hasSelectedDeliverableTarget ) {
					window.addEventListener( 'scroll', this.handleWindowScroll );

					this.selectedLanguageSlug = this.props.selectedLanguageSlug;

					const DEFAULT_LANGUAGE = 'en';
					setLocale( DEFAULT_LANGUAGE );
				} else {
					window.removeEventListener( 'scroll', this.handleWindowScroll );

					this.selectedLanguageSlug && this.props.setLocale( this.selectedLanguageSlug );
				}
			}
		);
	};

	renderDeliverableForm() {
		const { selectedDeliverableTarget, deliverableTitle } = this.state;
		const { translate } = this.props;

		if ( ! selectedDeliverableTarget ) {
			return;
		}

		const stringIdsCount = this.getOriginalIds().length;

		return (
			<div className="masterbar community-translator__bar">
				<form className="community-translator__bar-form" onSubmit={ this.handleDeliverableSubmit }>
					<div className="community-translator__bar-label">
						{ translate( '%d string found.', '%d strings found.', {
							count: stringIdsCount,
							args: [ stringIdsCount ],
						} ) }{ ' ' }
						{ translate( 'Enter a title:' ) }
					</div>

					<FormTextInput
						autoFocus // eslint-disable-line jsx-a11y/no-autofocus
						value={ deliverableTitle }
						onChange={ this.handleDeliverableTitleChange }
					/>

					<Button
						href={ this.getCreateDeliverableUrl() }
						target="_blank"
						onClick={ this.handleDeliverableLinkClick }
						primary
					>
						{ translate( 'Create Deliverable' ) }
					</Button>
					<Button onClick={ this.handleDeliverableCancelClick }>{ translate( 'Cancel' ) }</Button>
				</form>
			</div>
		);
	}

	renderDeliverableHighlight() {
		const { deliverableTarget, selectedDeliverableTarget, scrollTop } = this.state;
		const target = deliverableTarget || selectedDeliverableTarget;

		if ( ! target ) {
			return null;
		}

		const { left, top, width, height } = target.getBoundingClientRect();
		const style = {
			transform: `translate(${ left }px, ${ top + scrollTop }px)`,
			width: `${ width }px`,
			height: `${ height }px`,
		};

		return ReactDOM.createPortal(
			<Fragment>
				<div
					ref={ this.highlightRef }
					className="community-translator__highlight"
					style={ style }
				/>

				{ this.renderDeliverableForm() }
			</Fragment>,
			document.body
		);
	}

	renderConfirmationModal() {
		const { translate } = this.props;
		const infoDialogButtons = [ { action: 'cancel', label: translate( 'OK' ) } ];

		return (
			<Dialog
				isVisible
				buttons={ infoDialogButtons }
				onClose={ this.infoDialogClose }
				additionalClassNames="community-translator__modal"
			>
				<h1>{ translate( 'Community Translator' ) }</h1>
				<p>
					{ translate(
						'You have now enabled the translator. Right click the text to translate it.'
					) }
				</p>
				<p>
					<FormLabel htmlFor="toggle">
						<FormInputCheckbox id="toggle" onClick={ this.toggleInfoCheckbox } />
						<span>{ translate( "Don't show again" ) }</span>
					</FormLabel>
				</p>
			</Dialog>
		);
	}

	render() {
		const { translate, isEmpathyModeEnabled, selectedLanguageSlug } = this.props;
		const { isEnabled, isActive, infoDialogVisible } = this.state;

		const launcherClasses = clsx( 'community-translator', {
			'is-active': isActive,
			'is-incompatible': isEmpathyModeEnabled,
		} );
		const toggleString = isActive
			? translate( 'Disable Translator' )
			: translate( 'Enable Translator' );
		const toggleEmpathyModeString = getLanguageEmpathyModeActive()
			? 'Deactivate Empathy mode'
			: 'Activate Empathy mode';
		const buttonString = isEmpathyModeEnabled ? toggleEmpathyModeString : toggleString;
		const shouldRenderLauncherButton = isEnabled || isEmpathyModeEnabled;

		return (
			<Fragment>
				<QueryUserSettings />
				{ shouldRenderLauncherButton && (
					<Fragment>
						<div className={ launcherClasses }>
							<button
								onClick={ this.toggle }
								className="community-translator__button"
								title={ translate( 'Community Translator' ) }
							>
								<Gridicon icon="globe" />
								{ isEmpathyModeEnabled && (
									<span className="community-translator__badge">{ selectedLanguageSlug }</span>
								) }
								<div className="community-translator__text">{ buttonString }</div>
							</button>
						</div>
						{ infoDialogVisible && this.renderConfirmationModal() }
					</Fragment>
				) }
				{ this.renderDeliverableHighlight() }
			</Fragment>
		);
	}
}

export default connect(
	( state ) => ( {
		currentUser: getCurrentUser( state ),
		isUserSettingsReady: !! getUserSettings( state ),
		isTranslatorEnabled: getOriginalUserSetting( state, 'enable_translator' ),
		isEmpathyModeEnabled:
			config.isEnabled( 'i18n/empathy-mode' ) &&
			getOriginalUserSetting( state, 'i18n_empathy_mode' ),
		selectedLanguageSlug: getCurrentLocaleSlug( state ),
	} ),
	{ setLocale }
)( localize( TranslatorLauncher ) );
