import { useState } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import { ajaxPost } from '../../api/ajax';
import { useSettings } from '../../contexts/SettingsContext';
import { useNotices } from '../../contexts/NoticesContext';
import useSheetSync from '../../hooks/useSheetSync';
import { isWooActive } from '../../Helpers';
import Welcome from './Welcome';
import WooCommercePrompt from './WooCommercePrompt';
import StepHeader from './StepHeader';
import StepFooter from './StepFooter';
import HelpSidebar from './HelpSidebar';
import SyncProgress from '../../components/SyncProgress';
import Step1Credentials from './Step1Credentials';
import Step2SheetUrl from './Step2SheetUrl';
import Step3EditorAccess from './Step3EditorAccess';
import Step4AppsScript from './Step4AppsScript';
import Step5Sync from './Step5Sync';

const TEXT_DOMAIN = 'stock-sync-with-google-sheet-for-woocommerce';
const SHEET_URL_PATTERN = /^https:\/\/docs.google.com\/spreadsheets\/d\/[a-zA-Z0-9-_]+\/edit/;

// Steps 1 and 4 have two screens each; step 5 shows "Congratulations" as its second screen.
const STEPS_WITHOUT_SECOND_SCREEN = [ 2, 3 ];

export const hasCredentials = ( credentials ) =>
	!! credentials && typeof credentials === 'object' && !! credentials.client_email;

/**
 * Setup wizard (port of the removed templates/setup/* + the removed src/js/setup.js).
 */
const Setup = () => {
	const { options, applySavedOptions } = useSettings();
	const notices = useNotices();
	const { syncing, progress, title: syncTitle, runSync } = useSheetSync( 'setup' );

	const savedStep = Number( options.setup_step ) || 0;
	const [ started, setStarted ] = useState( savedStep > 0 );
	const [ currentStep, setCurrentStep ] = useState( savedStep || 1 );
	const [ screen, setScreen ] = useState( 1 );
	const [ direction, setDirection ] = useState( null );
	const [ loadingNext, setLoadingNext ] = useState( false );
	const [ wooActive, setWooActive ] = useState( isWooActive() );
	const [ draft, setDraft ] = useState( {
		spreadsheet_url: options.spreadsheet_url || '',
		sheet_tab: options.sheet_tab || 'Sheet1',
	} );
	const [ confirmations, setConfirmations ] = useState( {
		enabledApi: false,
		editorAccess: false,
		pastedScript: false,
		triggeredScript: false,
	} );

	const isFirstScreen = screen === 1;
	const confirm = ( key, value ) => setConfirmations( ( current ) => ( { ...current, [ key ]: value } ) );

	const saveOptions = async ( values ) => {
		const response = await ajaxPost( 'ssgsw_update_options', { options: values } );
		if ( response.success ) {
			applySavedOptions( values );
		}
		return response;
	};

	const showError = ( response, fallback ) => {
		notices.error(
			sprintf(
				/* translators: %s: error message. */
				__( 'FlexStock: %s', TEXT_DOMAIN ),
				response.message || fallback
			)
		);
	};

	const nextScreen = () => {
		if ( isFirstScreen && ! STEPS_WITHOUT_SECOND_SCREEN.includes( currentStep ) ) {
			setScreen( 2 );
		} else {
			setScreen( 1 );
			setCurrentStep( ( step ) => step + 1 );
		}
		setDirection( 'next' );
	};

	const previousScreen = () => {
		if ( isFirstScreen ) {
			setCurrentStep( ( step ) => step - 1 );
		}
		setScreen( 1 );
		setDirection( 'prev' );
	};

	const goToStep = ( step ) => {
		setCurrentStep( step );
		setScreen( 1 );
		setDirection( null );
	};

	const canGoNext = () => {
		switch ( currentStep ) {
			case 1:
				return isFirstScreen ? hasCredentials( options.credentials ) : confirmations.enabledApi;
			case 2:
				return SHEET_URL_PATTERN.test( draft.spreadsheet_url ) && draft.sheet_tab.trim().length > 0;
			case 3:
				return confirmations.editorAccess;
			case 4:
				return isFirstScreen ? confirmations.pastedScript : confirmations.triggeredScript;
			default:
				return false;
		}
	};

	const saveCredentials = async ( credentials, fileName ) => {
		const response = await ajaxPost( 'ssgsw_update_options', {
			options: {
				credentials: JSON.stringify( credentials ),
				credential_file: fileName,
				setup_step: 2,
			},
		} );

		if ( response.success ) {
			applySavedOptions( { credentials, credential_file: fileName, setup_step: 2 } );
			nextScreen();
		} else {
			showError( response, __( 'No product found. Try again', TEXT_DOMAIN ) );
		}
	};

	const handleNext = async () => {
		if ( loadingNext ) {
			return;
		}

		switch ( currentStep ) {
			case 1:
				if ( isFirstScreen ) {
					await saveCredentials( options.credentials, options.credential_file );
				} else {
					await saveOptions( { setup_step: 2 } );
					nextScreen();
				}
				break;

			case 2: {
				const response = await saveOptions( { ...draft, setup_step: 3 } );
				if ( response.success ) {
					nextScreen();
				} else {
					showError( response, __( 'Something went wrong', TEXT_DOMAIN ) );
				}
				break;
			}

			case 3: {
				setLoadingNext( true );
				const response = await ajaxPost( 'ssgsw_init_sheet' );
				setLoadingNext( false );

				if ( response.success ) {
					notices.success( __( 'FlexStock: Google Sheet is connected', TEXT_DOMAIN ) );
					await saveOptions( { setup_step: 4 } );
					nextScreen();
				} else {
					notices.alert(
						'error',
						__( 'FlexStock: Ops! Something went wrong', TEXT_DOMAIN ),
						sprintf(
							/* translators: %s: error message. */
							__( 'FlexStock: %s', TEXT_DOMAIN ),
							response.message || __( 'Something went wrong', TEXT_DOMAIN )
						)
					);
				}
				break;
			}

			case 4:
				if ( ! isFirstScreen ) {
					await saveOptions( { setup_step: 5, apps_script__notice: 1 } );
				}
				nextScreen();
				break;

			default:
				break;
		}
	};

	const handleSync = async () => {
		if ( await runSync() ) {
			nextScreen();
		}
	};

	if ( ! started ) {
		return (
			<>
				{ ! wooActive && <WooCommercePrompt onActivated={ () => setWooActive( true ) } /> }
				<Welcome onStart={ () => setStarted( true ) } />
			</>
		);
	}

	const paneProps = { isFirstScreen, direction };

	return (
		<>
			{ ! wooActive && <WooCommercePrompt onActivated={ () => setWooActive( true ) } /> }

			<div className="ssgs-setup-layout">
				<div className="ssgs-setup-main">
					<div className="ssgs-admin setup">
						<div className="ssgs-tab">
							<StepHeader currentStep={ currentStep } onSelect={ goToStep } />

							<div className="ssgs-tab__content">
								{ currentStep === 1 && (
									<Step1Credentials
										{ ...paneProps }
										credentialFile={ options.credential_file }
										onCredentials={ saveCredentials }
										enabledApi={ confirmations.enabledApi }
										onEnabledApiChange={ ( value ) => confirm( 'enabledApi', value ) }
									/>
								) }
								{ currentStep === 2 && (
									<Step2SheetUrl
										{ ...paneProps }
										values={ draft }
										onChange={ ( key, value ) => setDraft( ( current ) => ( { ...current, [ key ]: value } ) ) }
										urlInvalid={ draft.spreadsheet_url !== '' && ! SHEET_URL_PATTERN.test( draft.spreadsheet_url ) }
									/>
								) }
								{ currentStep === 3 && (
									<Step3EditorAccess
										{ ...paneProps }
										clientEmail={ hasCredentials( options.credentials ) ? options.credentials.client_email : '' }
										editorAccess={ confirmations.editorAccess }
										onEditorAccessChange={ ( value ) => confirm( 'editorAccess', value ) }
									/>
								) }
								{ currentStep === 4 && (
									<Step4AppsScript
										{ ...paneProps }
										options={ options }
										pastedScript={ confirmations.pastedScript }
										onPastedScriptChange={ ( value ) => confirm( 'pastedScript', value ) }
										triggeredScript={ confirmations.triggeredScript }
										onTriggeredScriptChange={ ( value ) => confirm( 'triggeredScript', value ) }
									/>
								) }
								{ currentStep >= 5 && (
									<Step5Sync
										{ ...paneProps }
										syncing={ syncing }
										onSync={ handleSync }
										spreadsheetUrl={ options.spreadsheet_url }
									/>
								) }
							</div>

							<StepFooter
								currentStep={ currentStep }
								isFirstScreen={ isFirstScreen }
								showPrevious={ ( currentStep > 1 || ! isFirstScreen ) && currentStep < 5 }
								showNext={ currentStep < 5 && canGoNext() }
								loadingNext={ loadingNext }
								onPrevious={ previousScreen }
								onNext={ handleNext }
							/>
						</div>
					</div>
				</div>

				<HelpSidebar />
			</div>

			{ syncing && <SyncProgress title={ syncTitle } progress={ progress } /> }
		</>
	);
};

export default Setup;
