/**
 * WordPress dependencies
 */
import apiFetch from '@safe-wordpress/api-fetch';
import {
	Button,
	Dashicon,
	Modal,
	TextControl,
	TextareaControl,
} from '@safe-wordpress/components';
import { useSelect } from '@safe-wordpress/data';
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 '@nelio-content/components';
import { store as NC_DATA } from '@nelio-content/data';
import type { Uuid, Url } from '@nelio-content/types';

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

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

type State = {
	readonly isModalOpen: boolean;
	readonly isDeactivating: boolean;
	readonly isLocked: 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 );

	if ( props.isDisabled ) {
		return (
			<div className="nelio-content-deactivation">
				<span>{ _x( 'Deactivate', 'command', 'nelio-content' ) }</span>
			</div>
		);
	}

	return (
		<div className="nelio-content-deactivation">
			<Button
				className="nelio-content-deactivation__button"
				variant="link"
				onClick={ state.openModal }
			>
				{ _x( 'Deactivate', 'command', 'nelio-content' ) }
			</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-content-deactivation__modal"
			title={ _x(
				'Nelio Content Deactivation',
				'text',
				'nelio-content'
			) }
			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-content-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, homeUrl, isSubscribed, apiUrl } = useSelect(
		( select ) => ( {
			siteId: select( NC_DATA ).getSiteId(),
			homeUrl: select( NC_DATA ).getHomeUrl(),
			isSubscribed: select( NC_DATA ).isSubscribed(),
			apiUrl: select( NC_DATA ).getApiRoot(),
		} ),
		[]
	);

	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-content' ) }
				disabled={ isTicketSubmitting }
				placeholder={ _x(
					'Tell us what’s going on',
					'user',
					'nelio-content'
				) }
				value={ description }
				onChange={ ( value ) =>
					setAttributes( { description: value } )
				}
			/>

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

			{ submissionError && (
				<p className="nelio-content-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-content'
							),
							'support@neliosoftware.com'
						) }
					</span>
				</p>
			) }

			<br />

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

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

const DefaultDeactivationBody = ( {
	isLocked,
	isSubscribed,
	mainActionLabel,
	cleanAndDeactivate,
	reason,
	setReason,
}: ModalState ): JSX.Element => (
	<>
		<p>
			{ _x(
				'If you have a moment, please share why you are deactivating Nelio Content:',
				'user',
				'nelio-content'
			) }
		</p>

		<RadioControl
			className="nelio-content-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 && (
			<p className="nelio-content-deactivation__warning">
				<Dashicon icon="warning" />
				<span>
					{ _x(
						'Please keep in mind your subscription to Nelio Content will remain active after removing the plugin from this site. If you want to unsubscribe from our service, you can do so from the plugin’s Account page before you deactivate the plugin.',
						'user',
						'nelio-content'
					) }
				</span>
			</p>
		) }

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

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

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

type ModalState = ReturnType< typeof useModalState >;
const useModalState = ( {
	cleanNonce,
	deactivationUrl,
	isSubscribed,
}: 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 = ( reason?: string ): void => {
		setState( { ...state, isDeactivating: true } );
		void apiFetch( {
			path: '/nelio-content/v1/plugin/clean',
			method: 'POST',
			data: { reason, _nonce: cleanNonce },
		} ).then(
			redirect, // on success
			closeModal // on error
		);
	};

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

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

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

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

		isLocked: state.isLocked,
		lock,

		reason: state.reason,
		setReason,
	};
};

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

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

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

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

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-content' ),
	},
	{
		value: 'clean-stuff',
		label: _x(
			'Delete Nelio Content’s data and deactivate plugin',
			'text',
			'nelio-content'
		),
	},
];

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-content' ),
	},
	{
		value: 'plugin-doesnt-work',
		label: _x(
			'I couldn’t get the plugin to work',
			'text',
			'nelio-content'
		),
	},
	{
		value: 'better-plugin-found',
		label: _x( 'I found a better plugin', 'text', 'nelio-content' ),
		extra: _x( 'What’s the plugin’s name?', 'text', 'nelio-content' ),
	},
	{
		value: 'other',
		label: _x( 'Other', 'text', 'nelio-content' ),
		extra: _x( 'Please share the reason…', 'user', 'nelio-content' ),
	},
];

function getDescription(
	description: string,
	siteId: Uuid,
	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 li0 = document.createElement( 'li' );
	li0.textContent = 'Plugin: Nelio Content';
	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( li0 );
	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;
}
