/**
 * WordPress dependencies
 */
import apiFetch from '@safe-wordpress/api-fetch';
import {
	Button,
	CheckboxControl,
	Dashicon,
	Modal,
	TextControl,
	TextareaControl,
} from '@safe-wordpress/components';
import { useState } from '@safe-wordpress/element';
import { _x, sprintf } from '@safe-wordpress/i18n';
import { isEmail } from '@safe-wordpress/url';

/**
 * External dependencies
 */
import { trim } from 'lodash';
import { RadioControl } from '@nab/components';
import { usePluginSetting } from '@nab/data';
import type { SiteId, Url } from '@nab/types';

/**
 * Internal dependencies
 */
import './style.scss';

export type DeactivationActionProps = {
	readonly isSubscribed: boolean;
	readonly isStagingSite: boolean;
	readonly cleanNonce: string;
	readonly deactivationUrl: string;
};

type State = {
	readonly isModalOpen: boolean;
	readonly isDeactivating: boolean;
	readonly isLocked: boolean;
	readonly deleteStagingDataOnly: boolean;
	readonly reason: {
		readonly value:
			| 'temporary-deactivation'
			| 'clean-stuff'
			| 'plugin-no-longer-needed'
			| 'plugin-doesnt-work'
			| 'better-plugin-found'
			| 'other';
		readonly details: string;
	};
};

type ContactFormState = {
	readonly isTicketSubmitting: boolean;
	readonly description: string;
	readonly email: string;
	readonly submissionError: boolean;
};

export const DeactivationAction = (
	props: DeactivationActionProps
): JSX.Element => {
	const state = useModalState( props );

	return (
		<div className="nelio-ab-testing-deactivation">
			<Button
				className="nelio-ab-testing-deactivation__button"
				variant="link"
				onClick={ state.openModal }
			>
				{ _x( 'Deactivate', 'command', 'nelio-ab-testing' ) }
			</Button>

			<DeactivationModal state={ state } />
		</div>
	);
};

// =============
// HELPERS VIEWS
// =============

type DeactivationModalProps = {
	readonly state: ModalState;
};
const DeactivationModal = ( {
	state,
}: DeactivationModalProps ): JSX.Element | null => {
	if ( ! state.isModalOpen ) {
		return null;
	}

	let Body: typeof DefaultDeactivationBody;
	switch ( state.reason.value ) {
		case 'temporary-deactivation':
			Body = TemporaryDeactivationBody;
			break;
		case 'plugin-doesnt-work':
			Body = ContactFormBody;
			break;
		default:
			Body = DefaultDeactivationBody;
	}

	return (
		<Modal
			className="nelio-ab-testing-deactivation__modal"
			title={ _x(
				'Nelio A/B Testing Deactivation',
				'text',
				'nelio-ab-testing'
			) }
			isDismissible={ ! state.isLocked }
			shouldCloseOnEsc={ ! state.isLocked }
			shouldCloseOnClickOutside={ ! state.isLocked }
			onRequestClose={ state.closeModal }
		>
			<Body { ...state } />
		</Modal>
	);
};

const TemporaryDeactivationBody = ( {
	deactivate,
	isDeactivating,
	mainActionLabel,
	reason,
	setReason,
}: ModalState ): JSX.Element => (
	<>
		<RadioControl
			selected={ reason.value }
			options={ DEACTIVATION_MODES }
			onChange={ ( value: State[ 'reason' ][ 'value' ] ) =>
				setReason( { value, details: '' } )
			}
			disabled={ isDeactivating }
		/>
		<br />
		<div className="nelio-ab-testing-deactivation__actions">
			<span></span>

			<Button
				variant="primary"
				disabled={ isDeactivating || 'clean-stuff' === reason.value }
				onClick={ () => deactivate() }
			>
				{ mainActionLabel }
			</Button>
		</div>
	</>
);

const ContactFormBody = ( {
	closeModal,
	lock,
	setReason,
}: ModalState ): JSX.Element => {
	const [ state, setState ] = useState( INIT_CONTACT_FORM_STATE );
	const { isTicketSubmitting, description, email, submissionError } = state;
	const isFormValid = trim( description ).length && isEmail( email );

	const setAttributes = ( attrs: Partial< ContactFormState > ) =>
		setState( { ...state, ...attrs } );

	const siteId = usePluginSetting( 'siteId' );
	const homeUrl = usePluginSetting( 'homeUrl' );
	const isSubscribed = !! usePluginSetting( 'subscription' );
	const apiUrl = usePluginSetting( 'apiUrl' );

	const sendTicket = () => {
		lock();
		setAttributes( { isTicketSubmitting: true } );
		void apiFetch( {
			url: `${ apiUrl }/ticket`,
			credentials: 'omit',
			method: 'POST',
			mode: 'cors',
			data: {
				email,
				description: getDescription(
					description,
					siteId,
					homeUrl,
					isSubscribed
				),
				subject: 'I can’t get the plugin to work and need help',
			},
		} )
			.then( closeModal )
			.catch( () => {
				setAttributes( {
					submissionError: true,
					isTicketSubmitting: false,
				} );
				lock( false );
			} );
	};

	return (
		<>
			<TextareaControl
				label={ _x( 'The Problem:', 'text', 'nelio-ab-testing' ) }
				disabled={ isTicketSubmitting }
				placeholder={ _x(
					'Tell us what’s going on',
					'user',
					'nelio-ab-testing'
				) }
				value={ description }
				onChange={ ( value ) =>
					setAttributes( { description: value } )
				}
			/>

			<TextControl
				label={ _x( 'Your Email:', 'text', 'nelio-ab-testing' ) }
				disabled={ isTicketSubmitting }
				value={ email }
				onChange={ ( value ) => setAttributes( { email: value } ) }
			/>

			{ submissionError && (
				<p className="nelio-ab-testing-deactivation__warning">
					<Dashicon icon="warning" />
					<span>
						{ sprintf(
							/* translators: %s: Email address. */
							_x(
								'Something went wrong and we couldn’t receive your support request. Please try again later or send us an email to %s.',
								'user',
								'nelio-ab-testing'
							),
							'support@neliosoftware.com'
						) }
					</span>
				</p>
			) }

			<br />

			<div className="nelio-ab-testing-deactivation__actions">
				<Button
					variant="link"
					onClick={ () =>
						setReason( { value: 'other', details: '' } )
					}
				>
					{ _x( 'Back', 'command', 'nelio-ab-testing' ) }
				</Button>

				<Button
					variant="primary"
					disabled={ ! isFormValid || isTicketSubmitting }
					isBusy={ isTicketSubmitting }
					onClick={ sendTicket }
				>
					{ isTicketSubmitting
						? _x( 'Submitting…', 'text', 'nelio-ab-testing' )
						: _x(
								'Submit and Keep Plugin',
								'command',
								'nelio-ab-testing'
						  ) }
				</Button>
			</div>
		</>
	);
};

const DefaultDeactivationBody = ( {
	isLocked,
	isSubscribed,
	isStagingSite,
	mainActionLabel,
	cleanAndDeactivate,
	reason,
	setReason,
	deleteStagingDataOnly,
	setDeleteStagingDataOnly,
}: ModalState ): JSX.Element => (
	<>
		<p>
			{ _x(
				'If you have a moment, please share why you are deactivating Nelio A/B Testing:',
				'user',
				'nelio-ab-testing'
			) }
		</p>

		<RadioControl
			className="nelio-ab-testing-deactivation__options"
			selected={ reason.value }
			options={ DEACTIVATION_REASONS }
			onChange={ ( value: State[ 'reason' ][ 'value' ] ) =>
				setReason( { value, details: '' } )
			}
			extraValue={ reason.details }
			onExtraChange={ ( details ) => setReason( { ...reason, details } ) }
			disabled={ isLocked }
		/>

		{ isSubscribed && isStagingSite && (
			<p className="nelio-ab-testing-deactivation__staging-check">
				<CheckboxControl
					label={ _x(
						'Delete staging data only',
						'text',
						'nelio-ab-testing'
					) }
					checked={ deleteStagingDataOnly }
					onChange={ setDeleteStagingDataOnly }
					help={ _x(
						'Keep this checked to delete data on this staging site only, while preserving data on your live site.',
						'user',
						'nelio-ab-testing'
					) }
				/>
			</p>
		) }

		{ isSubscribed && (
			<p className="nelio-ab-testing-deactivation__warning">
				<Dashicon icon="warning" />
				<span>
					{ _x(
						'Deactivating the plugin does not cancel your Nelio A/B Testing subscription. To unsubscribe, visit the plugin’s Account page first.',
						'user',
						'nelio-ab-testing'
					) }
				</span>
			</p>
		) }

		<div className="nelio-ab-testing-deactivation__actions">
			{ isLocked ? (
				<span></span>
			) : (
				<Button
					variant="link"
					disabled={ isLocked }
					onClick={ () =>
						cleanAndDeactivate( deleteStagingDataOnly )
					}
				>
					{ _x( 'Just Delete Data', 'command', 'nelio-ab-testing' ) }
				</Button>
			) }

			<Button
				variant="primary"
				disabled={ isLocked || 'clean-stuff' === reason.value }
				onClick={ () =>
					cleanAndDeactivate(
						deleteStagingDataOnly,
						! reason.details
							? reason.value
							: `${ reason.value }: ${ reason.details }`
					)
				}
			>
				{ mainActionLabel }
			</Button>
		</div>
	</>
);

// =====
// HOOKS
// =====

type ModalState = ReturnType< typeof useModalState >;
const useModalState = ( {
	cleanNonce,
	deactivationUrl,
	isSubscribed,
	isStagingSite,
}: DeactivationActionProps ) => {
	const [ state, setState ] = useState( INIT_STATE );

	const redirect = () => {
		window.location.href = deactivationUrl;
	};

	const openModal = () =>
		setState( {
			...INIT_STATE,
			isModalOpen: true,
		} );

	const closeModal = () =>
		setState( {
			...INIT_STATE,
			isModalOpen: false,
		} );

	const deactivate = () => {
		setState( {
			...state,
			reason: INIT_STATE.reason,
			isDeactivating: true,
			isLocked: true,
		} );
		redirect();
	};

	const lock = ( isLocked = true ) => setState( { ...state, isLocked } );

	const cleanAndDeactivate = (
		deleteStagingDataOnly: boolean,
		reason?: string
	): void => {
		setState( { ...state, isDeactivating: true } );
		void apiFetch( {
			path: '/nab/v1/plugin/clean',
			method: 'POST',
			data: { deleteStagingDataOnly, reason, nabnonce: cleanNonce },
		} ).then(
			redirect, // on success
			closeModal // on error
		);
	};

	const setReason = ( reason: State[ 'reason' ] ) =>
		setState( { ...state, reason } );

	const setDeleteStagingDataOnly = ( deleteStagingDataOnly: boolean ) =>
		setState( { ...state, deleteStagingDataOnly } );

	const mainActionLabel =
		'temporary-deactivation' === state.reason.value
			? getDeactivationLabel( state.isDeactivating )
			: getCleanAndDeactivateLabel( state.isDeactivating );

	return {
		isModalOpen: state.isModalOpen,
		openModal,
		closeModal,

		isDeactivating: state.isDeactivating,
		isSubscribed,
		isStagingSite,
		mainActionLabel,
		deactivate,
		cleanAndDeactivate,

		isLocked: state.isLocked,
		lock,

		reason: state.reason,
		setReason,

		deleteStagingDataOnly: state.deleteStagingDataOnly,
		setDeleteStagingDataOnly,
	};
};

const getDeactivationLabel = ( isDeactivating: boolean ) =>
	isDeactivating
		? _x( 'Deactivating…', 'text', 'nelio-ab-testing' )
		: _x( 'Deactivate', 'command', 'nelio-ab-testing' );

const getCleanAndDeactivateLabel = ( isDeleting: boolean ) =>
	isDeleting
		? _x( 'Deleting Data…', 'text', 'nelio-ab-testing' )
		: _x( 'Submit and Delete Data', 'command', 'nelio-ab-testing' );

// ====
// DATA
// ====

const INIT_STATE: State = {
	isModalOpen: false,
	isDeactivating: false,
	isLocked: false,
	reason: {
		value: 'temporary-deactivation',
		details: '',
	},
	deleteStagingDataOnly: true,
};

const INIT_CONTACT_FORM_STATE: ContactFormState = {
	isTicketSubmitting: false,
	email: '',
	description: '',
	submissionError: false,
};

const DEACTIVATION_MODES: ReadonlyArray< {
	readonly value: State[ 'reason' ][ 'value' ];
	readonly label: string;
} > = [
	{
		value: 'temporary-deactivation',
		label: _x(
			'It’s a temporary deactivation',
			'text',
			'nelio-ab-testing'
		),
	},
	{
		value: 'clean-stuff',
		label: _x(
			'Delete Nelio A/B Testing’s data and deactivate plugin',
			'text',
			'nelio-ab-testing'
		),
	},
];

const DEACTIVATION_REASONS: ReadonlyArray< {
	readonly value: State[ 'reason' ][ 'value' ];
	readonly label: string;
	readonly extra?: string;
} > = [
	{
		value: 'plugin-no-longer-needed',
		label: _x( 'I no longer need the plugin', 'text', 'nelio-ab-testing' ),
	},
	{
		value: 'plugin-doesnt-work',
		label: _x(
			'I couldn’t get the plugin to work',
			'text',
			'nelio-ab-testing'
		),
	},
	{
		value: 'better-plugin-found',
		label: _x( 'I found a better plugin', 'text', 'nelio-ab-testing' ),
		extra: _x( 'What’s the plugin’s name?', 'text', 'nelio-ab-testing' ),
	},
	{
		value: 'other',
		label: _x( 'Other', 'text', 'nelio-ab-testing' ),
		extra: _x( 'Please share the reason…', 'user', 'nelio-ab-testing' ),
	},
];

function getDescription(
	description: string,
	siteId: SiteId,
	homeUrl: Url,
	isSubscribed: boolean
): string {
	const div = document.createElement( 'div' );
	const br = () => document.createElement( 'br' );

	const extra = document.createElement( 'strong' );
	extra.textContent = 'Additional Information';

	const ul = document.createElement( 'ul' );
	const li1 = document.createElement( 'li' );
	li1.textContent = `Site ID: ${ siteId }`;
	const li2 = document.createElement( 'li' );
	li2.textContent = `Site URL: ${ homeUrl }`;
	const li3 = document.createElement( 'li' );
	li3.textContent = `Subscribed: ${ isSubscribed ? 'yes' : 'no' }`;
	ul.appendChild( li1 );
	ul.appendChild( li2 );
	ul.appendChild( li3 );

	trim( description )
		.split( /\n+/ )
		.forEach( ( t ) => {
			const p = document.createTextNode( t );
			div.appendChild( p );
			div.appendChild( br() );
			div.appendChild( br() );
		} );

	div.appendChild( extra );
	div.appendChild( br() );
	div.appendChild( ul );

	return div.innerHTML;
}
