// @ts-check
/* global genesisBlocksMigration */

/**
 * External dependencies
 */
import * as React from 'react';

/**
 * WordPress dependencies
 */
import { speak } from '@wordpress/a11y';
import apiFetch from '@wordpress/api-fetch';
import { useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import { Step, StepContent, StepFooter, StepIcon, SubstepList } from '../';

/**
 * @typedef {Object} MigrateBlocksProps The component props.
 * @property {Function} goToNext       Goes to the next step.
 * @property {boolean}  isStepActive   Whether this step is active.
 * @property {boolean}  isStepComplete Whether this step is complete.
 * @property {number}   stepIndex      The step index of this step.
 */

/**
 * The step that migrates the blocks.
 *
 * @param {MigrateBlocksProps} Props The component props.
 * @return {React.ReactElement} The component to prompt to migrate the post content.
 */
const MigrateBlocks = ({
	isStepActive,
	isStepComplete,
	stepIndex,
	goToNext,
}) => {
	const [currentBlockMigrationStep, setCurrentBlockMigrationStep] =
		useState(0);
	const [isInProgress, setIsInProgress] = useState(false);
	const [isError, setIsError] = useState(false);
	const [errorMessage, setErrorMessage] = useState('');
	const [isSuccess, setIsSuccess] = useState(false);
	const [postsMigrated, setPostsMigrated] = useState(0);

	const migrationLabels = [
		__('Migrate block settings.', 'genesis-blocks'),
		__('Migrate block content. Migrated: ', 'genesis-blocks') +
			` ${postsMigrated}.`,
		__('Migrate favorite blocks.', 'genesis-blocks'),
		genesisBlocksMigration.isPro
			? __('Clean up.', 'genesis-blocks')
			: __('Deactivate Atomic Blocks.', 'genesis-blocks'),
	];

	/**
	 * Step 1: Migrates block settings, then triggers step 2.
	 */
	const migrateBlockSettings = async () => {
		await apiFetch({
			path: '/genesis-blocks/migrate-settings',
			method: 'POST',
		})
			.then(async () => {
				setCurrentBlockMigrationStep(1);
				await migrateProBlockSettings();
				await migratePostContent();
			})
			.catch((result) => {
				if (result.hasOwnProperty('message')) {
					setErrorMessage(result.message);
				}
				speak(
					__(
						'The migration failed during settings migration.',
						'genesis-blocks'
					)
				);
				setIsError(true);
				setIsInProgress(false);
			});
	};

	const migrateProBlockSettings = async () => {
		await apiFetch({
			path: '/genesis-blocks/migrate-pro-settings',
			method: 'POST',
		}).catch((result) => {
			if (result.hasOwnProperty('message')) {
				setErrorMessage(result.message);
			}
			speak(__('The pro settings migration failed.', 'genesis-blocks'));
			setIsError(true);
		});
	};

	/**
	 * Step 2: Migrates post content, then triggers step 3.
	 */
	const migratePostContent = async () => {
		// Used for a 504 Gateway Timeout Error, but could also be for other errors.
		const timeoutErrorCode = 'invalid_json';

		await apiFetch({
			path: '/genesis-blocks/migrate-content',
			method: 'POST',
		})
			.then(async (response) => {
				// Send migration requests until no posts with Atomic Blocks content are found.
				if (response.results && response.results.postsFound > 0) {
					setPostsMigrated(
						(postsMigrated) =>
							postsMigrated + response.results.postsFound
					);
					await migratePostContent();
					return;
				}
				setCurrentBlockMigrationStep(2);
				await migrateFavoriteBlocks();
			})
			.catch(async (result) => {
				if (
					result.hasOwnProperty('code') &&
					timeoutErrorCode === result.code
				) {
					await migratePostContent();
					return;
				} else if (result.hasOwnProperty('message')) {
					setErrorMessage(result.message);
				}

				speak(
					__(
						'The migration failed during post content migration',
						'genesis-blocks'
					)
				);
				setIsError(true);
			});
	};

	/**
	 * Step 3: Migrates favorite blocks, then triggers step 3.
	 */
	const migrateFavoriteBlocks = async () => {
		// Used for a 504 Gateway Timeout Error, but could also be for other errors.
		const timeoutErrorCode = 'invalid_json';

		await apiFetch({
			path: '/genesis-blocks/migrate-user-meta',
			method: 'POST',
		})
			.then(async () => {
				setCurrentBlockMigrationStep(3);
				await cleanup();
			})
			.catch(async (result) => {
				if (
					result.hasOwnProperty('code') &&
					timeoutErrorCode === result.code
				) {
					await migrateFavoriteBlocks();
					return;
				} else if (result.hasOwnProperty('message')) {
					setErrorMessage(result.message);
				}

				speak(
					__(
						'The migration failed while migrating favorite blocks.',
						'genesis-blocks'
					)
				);
				setIsError(true);
			});
	};

	/**
	 * Step 4: Deactivates Atomic Blocks and toggles migration options.
	 */
	const cleanup = async () => {
		/**
		 * Await responses before showing success state, but discard errors.
		 * - Plugin deactivation will 404 if Atomic Blocks is not present,
		 *   but no further action is required.
		 * - Option deletion can ‘fail’ if no option exists, like when the user
		 *   did not migrate via the prompt in Atomic Blocks.
		 */
		await apiFetch({
			path: '/genesis-blocks/migrate-cleanup',
			method: 'POST',
		}).then(() => {
			speak(__('The migration was successful!', 'genesis-blocks'));
			setIsSuccess(true);
			goToNext();
		});
	};

	/**
	 * Sets initial migration state and begins migration step 1.
	 */
	const migrate = async () => {
		speak(__('The migration is now in progress', 'genesis-blocks'));
		setErrorMessage('');
		setIsInProgress(true);

		// Starts the first migration step. Subsequent steps are chained to this step.
		await migrateBlockSettings();

		setIsInProgress(false);
	};

	return (
		<Step isActive={isStepActive} isComplete={isStepComplete}>
			<StepIcon index={stepIndex} isComplete={isStepComplete} />
			<StepContent
				heading={__('Migrate Your Content', 'genesis-blocks')}
				isStepActive={isStepActive}
				isLastStep={true}
			>
				{!isSuccess && (
					<p>
						{__(
							'Okay! Everything is ready. Let’s do this. While the migration is underway, don’t leave this page.',
							'genesis-blocks'
						)}
					</p>
				)}
				{!!errorMessage && (
					<div className="gb-migration__error inline-notice gb-error">
						<p>
							<span>
								{__(
									'The following error occurred:',
									'genesis-blocks'
								)}
							</span>
							{errorMessage}
						</p>
					</div>
				)}
				{(isInProgress || isSuccess) && (
					<>
						<SubstepList
							steps={migrationLabels}
							currentStep={currentBlockMigrationStep}
							complete={!isInProgress}
						/>
					</>
				)}
				{!isInProgress && !isSuccess && (
					<button
						className="gb-admin-button-primary"
						onClick={migrate}
					>
						{isError
							? __('Try Again', 'genesis-blocks')
							: __('Migrate Now', 'genesis-blocks')}
					</button>
				)}
				{isSuccess && (
					<>
						{!genesisBlocksMigration.isPro && (
							<p>
								<span
									role="img"
									aria-label={__(
										'party emoji',
										'genesis-blocks'
									)}
								>
									🎉
								</span>
								&nbsp;
								{__(
									'The migration completed successfully! Time to say goodbye to Atomic Blocks (it’s been fun!) and step into the FUTURE',
									'genesis-blocks'
								)}
								&nbsp;
								<span className="message-future">
									{__('FUTURE', 'genesis-blocks')}
								</span>
								&nbsp;
								<sub>{__('FUTURE', 'genesis-blocks')}</sub>.
							</p>
						)}
						{genesisBlocksMigration.isPro && (
							<p>
								<span
									role="img"
									aria-label={__(
										'party emoji',
										'genesis-blocks'
									)}
								>
									🎉
								</span>
								&nbsp;
								{__(
									'The migration completed successfully!',
									'genesis-blocks'
								)}
							</p>
						)}
						<StepFooter>
							{/* @ts-ignore */}
							<a
								href={genesisBlocksMigration.gbUrl}
								className="btn"
							>
								{__(
									'Get started with Genesis Blocks',
									'genesis-blocks'
								)}
							</a>
						</StepFooter>
					</>
				)}
			</StepContent>
		</Step>
	);
};

export default MigrateBlocks;
