import { useState, useEffect } from 'react';
import { useBoundStore } from '../../store/store';
import {
	initialProductMappingsState,
	initialColumnMappingsState,
	initialRowMappingsState,
} from './initial-state';
import { getRowConditionLabel } from './get-row-condition-product-name';
import type { Product } from '../../typings/types';
import {
	getProductFields,
	getAdditionalConditionalLogicFieldOptions,
} from '../../utilities';
import { __ } from '@wordpress/i18n';

const { gp_conditional_pricing_form_settings_strings: strings } = window;

interface SaveImportedPricingRuleMappingsResponse {
	success: boolean;
	data: {
		products: Product[];
		import_counts: {
			pricing_levels: number;
			products: number;
		};
	};
}

interface FieldMappingFormProps {}

export function FieldMappingForm(props: FieldMappingFormProps) {
	const {
		setProducts,
		setImportCounts,
		setHasUnsavedChanges,
		disambiguation,
		filePath,
		fileContents,
		setActiveView,
		addBanner,
	} = useBoundStore((state) => ({
		setProducts: state.setProducts,
		setImportCounts: state.setImportCounts,
		setHasUnsavedChanges: state.setHasUnsavedChanges,
		disambiguation: state.disambiguation,
		filePath: state.filePath,
		fileContents: state.fileContents,
		setActiveView: state.setActiveView,
		addBanner: state.addBanner,
	}));

	// productMappings is a map of product slugs to id of the product field id it has been mapped to.
	const [productMappings, setProductMappings] = useState<
		Record<string, string>
	>(() => initialProductMappingsState(disambiguation));

	// columnMappings is a map of column indexes (along the x-axis) to id of the field it has been mapped to.
	const [columnMappings, setColumnMappings] = useState<
		Record<string, string>
	>(() => initialColumnMappingsState(disambiguation, fileContents || []));

	// rowMappings is a map of row indexes (along the y-axis) to the id of the field it has been mapped to.
	const [rowMappings, setRowMappings] = useState<Record<string, string>>(() =>
		initialRowMappingsState(disambiguation, fileContents)
	);

	const [importStrategy, setImportStrategy] = useState<
		'append' | 'replace_all' | 'replace_matching' | null
	>(null);

	const [importButtonDisabled, setImportButtonDisabled] = useState(true);

	/**
	 * Set the disabled state of the import button to "true" if any mapping or an import strategy is not set.
	 */
	useEffect(() => {
		setProductMappings(initialProductMappingsState(disambiguation));
		setColumnMappings(
			initialColumnMappingsState(disambiguation, fileContents)
		);
		setRowMappings(initialRowMappingsState(disambiguation, fileContents));
	}, [disambiguation, fileContents]);

	useEffect(() => {
		for (const product of disambiguation?.products ?? []) {
			if (!productMappings[product.slug]) {
				setImportButtonDisabled(true);
				return;
			}
		}

		for (const column of disambiguation?.columns ?? []) {
			if (!columnMappings[column.index]) {
				setImportButtonDisabled(true);
				return;
			}
		}

		for (const row of disambiguation?.rows ?? []) {
			if (!rowMappings[row.index]) {
				setImportButtonDisabled(true);
				return;
			}
		}

		if (!importStrategy) {
			setImportButtonDisabled(true);
			return;
		}

		setImportButtonDisabled(false);
	}, [
		disambiguation,
		productMappings,
		columnMappings,
		rowMappings,
		importStrategy,
	]);

	const handleImportStrategyChange = (
		event: React.ChangeEvent<HTMLInputElement>
	) => {
		const value = event.target.value as
			| 'append'
			| 'replace_all'
			| 'replace_matching';
		setImportStrategy(value);
		setImportButtonDisabled(false);
	};

	const handleRuleMappingSubmit = async (
		event: React.FormEvent<HTMLFormElement>
	) => {
		event.preventDefault();

		const confirmations = [
			{
				strategy: 'replace_all',
				message: __(
					'Are you sure you want to replace all existing pricing rules with this import?',
					'gp-conditional-pricing'
				),
			},
			{
				strategy: 'replace_matching',
				message: __(
					'Are you sure you want to replace pricing rules for matching products in this import?',
					'gp-conditional-pricing'
				),
			},
		];

		for (const { strategy, message } of confirmations) {
			// eslint-disable-next-line no-alert
			if (importStrategy === strategy && !confirm(message)) {
				return;
			}
		}

		try {
			const resp: SaveImportedPricingRuleMappingsResponse =
				await jQuery.post(strings.ajax_url, {
					action: 'gwcp_save_imported_pricing_rule_mappings',
					_ajax_nonce: strings.nonce,
					form_id: strings.form_id,
					file_path: filePath,
					product_mappings: productMappings,
					column_mappings: columnMappings,
					row_mappings: rowMappings,
					import_strategy: importStrategy,
				});

			setProducts(resp.data.products);
			setHasUnsavedChanges(true);
			setImportCounts({
				products: resp.data.import_counts.products,
				pricingLevels: resp.data.import_counts.pricing_levels,
			});
			setActiveView('pricing-rules');
		} catch (error) {
			addBanner(
				__('Error importing pricing rules.', 'gp-conditional-pricing'),
				'error'
			);

			// eslint-disable-next-line no-console
			console.error(error);
		}
	};

	if (!disambiguation) {
		return <div>{__('Loading…', 'gp-conditional-pricing')}</div>;
	}

	const additionalFieldOptions = getAdditionalConditionalLogicFieldOptions();

	const replaceAllId = 'gpcp-import-type-replace-all';
	const replaceMatchingId = 'gpcp-import-type-replace-matching';
	const appendId = 'gpcp-import-type-append';

	return (
		<form
			id="gpcp-importer-disambiguation"
			name="gpcp-importer-disambiguation"
			action="<?php echo remove_query_arg( 'tab' ); ?>"
			method="post"
			encType="multipart/form-data"
			onSubmit={handleRuleMappingSubmit}
			className="gform_settings_form"
		>
			{disambiguation?.products.length > 0 && (
				<fieldset className="gform-settings-panel gform-settings-panel--with-title gform-settings-panel--full">
					<legend className="gform-settings-panel__title gform-settings-panel__title--header">
						{__(
							'Import Mapping: Products',
							'gp-conditional-pricing'
						)}
					</legend>

					<div className="gform-settings-panel__content">
						<div className="gwcp-choose-import-file-message-grey-background">
							<p className="instructions">
								{__(
									'Select which fields on this form correspond to each of the products parsed from your import file.',
									'gp-conditional-pricing'
								)}
							</p>
						</div>
						<ul className="gpcp-importer-fields">
							<li className="gwcp-import-mapping-card-li">
								<span>
									{__(
										'Import Product',
										'gp-conditional-pricing'
									)}
								</span>
								<span>
									{__(
										'Form Product',
										'gp-conditional-pricing'
									)}
								</span>
							</li>
							{disambiguation.products.map((product, i) => {
								const { slug } = product;
								return (
									<li
										key={`${slug}_${i}`}
										className="gwcp-import-mapping-card-li"
									>
										<label htmlFor={slug}>
											{product.name}
										</label>
										<select
											id={`product_${slug}`}
											name={'product_${slug'}
											value={productMappings[slug] ?? ''}
											onChange={(
												event: React.ChangeEvent<HTMLSelectElement>
											) => {
												setProductMappings((prev) => ({
													...prev,
													[slug]: event.target.value,
												}));
											}}
										>
											<option value="">
												&mdash;{' '}
												{__(
													'Select a product',
													'gp-conditional-pricing'
												)}{' '}
												&mdash;
											</option>
											{getProductFields().map((field) => (
												<option
													key={`field_${field.id}`}
													value={field.id}
												>
													{field.label}
												</option>
											))}
										</select>
									</li>
								);
							})}
						</ul>
					</div>
				</fieldset>
			)}

			{disambiguation?.columns.length > 0 && (
				<fieldset className="gform-settings-panel gform-settings-panel--with-title gform-settings-panel--full">
					<legend className="gform-settings-panel__title gform-settings-panel__title--header">
						{__(
							'Import Mapping: Column Conditions',
							'gp-conditional-pricing'
						)}
					</legend>

					<div className="gform-settings-panel__content">
						<div className="gwcp-choose-import-file-message-grey-background">
							<p className="instructions">
								{__(
									'Select which fields on this form correspond to each of the condition columns from the import file.',
									'gp-conditional-pricing'
								)}
							</p>
						</div>

						<ul className="gpcp-importer-columns gpcp-importer-fields">
							<li className="gwcp-import-mapping-card-li">
								<span>
									{__(
										'Import Column',
										'gp-conditional-pricing'
									)}
								</span>
								<span>
									{__('Form Field', 'gp-conditional-pricing')}
								</span>
							</li>
							{disambiguation.columns.map((column, index) => (
								<li
									key={`column_${column}_${index}`}
									className="gwcp-import-mapping-card-li"
								>
									<label htmlFor={`column_${index}`}>
										{column.name}
									</label>
									<select
										id={`column_${index}`}
										name={`column_${index}`}
										value={columnMappings[column.index]}
										onChange={(
											event: React.ChangeEvent<HTMLSelectElement>
										) => {
											setColumnMappings((prev) => ({
												...prev,
												[column.index]:
													event.target.value,
											}));
										}}
									>
										<option value="">
											&mdash;{' '}
											{__(
												'Select a field',
												'gp-conditional-pricing'
											)}{' '}
											&mdash;
										</option>
										{window.form.fields.map(
											(field, fieldIndex) => {
												if (field.inputs) {
													return field.inputs.map(
														(
															input: GFFieldInput
														) => (
															<option
																key={`column_field_option_${column}_${fieldIndex}_${input.id}`}
																value={input.id}
															>
																{field.label} (
																{input.label})
															</option>
														)
													);
												}

												return (
													<option
														key={`column_field_option_${column}_${index}_${field.id}`}
														value={field.id}
													>
														{field.label}
													</option>
												);
											}
										)}
										{additionalFieldOptions.map(
											(option) => (
												<option
													key={`column_field_option_${column.index}_${option.value}`}
													value={option.value}
												>
													{option.label}
												</option>
											)
										)}
									</select>
								</li>
							))}
						</ul>
					</div>
				</fieldset>
			)}

			{disambiguation?.rows.length > 0 && (
				<fieldset className="gform-settings-panel gform-settings-panel--with-title gform-settings-panel--full">
					<legend className="gform-settings-panel__title gform-settings-panel__title--header">
						{__(
							'Import Mapping: Row Conditions',
							'gp-conditional-pricing'
						)}
					</legend>

					<div className="gform-settings-panel__content">
						<div className="gwcp-choose-import-file-message-grey-background">
							<p className="instructions">
								{__(
									'Select which fields on this form correspond to the each of the condition rows from the import file.',
									'gp-conditional-pricing'
								)}
							</p>
						</div>
						<ul className="gpcp-importer-rows gpcp-importer-fields">
							<li className="gwcp-import-mapping-card-li">
								<span>
									{__('Import Row', 'gp-conditional-pricing')}
								</span>
								<span>
									{__('Form Field', 'gp-conditional-pricing')}
								</span>
							</li>
							{disambiguation.rows.map((row) => {
								return (
									<li
										key={`row_mapping_${row.index}`}
										className="gwcp-import-mapping-card-li"
									>
										<label htmlFor={`row_${row.index}`}>
											{getRowConditionLabel(
												row,
												fileContents || []
											)}
										</label>
										<select
											id={`row_${row.index}`}
											name={`row_${row.index}`}
											value={rowMappings[row.index]}
											onChange={(
												event: React.ChangeEvent<HTMLSelectElement>
											) => {
												setRowMappings((prev) => ({
													...prev,
													[row.index]:
														event.target.value,
												}));
											}}
										>
											<option value="">
												&mdash;{' '}
												{__(
													'Select a field',
													'gp-conditional-pricing'
												)}{' '}
												&mdash;
											</option>
											{window.form.fields.map((field) => (
												<>
													<option
														key={`row_${row.index}_${field.id}`}
														value={field.id}
													>
														{field.label}
													</option>
													{field.inputType ===
														'singleproduct' && (
														<option
															key={`quantity_row_${row.index}_${field.id}`}
															value={`quantity_${field.id}`}
														>
															{`${field.label} (Quantity)`}
														</option>
													)}
												</>
											))}
										</select>
									</li>
								);
							})}
						</ul>
					</div>
				</fieldset>
			)}
			<fieldset className="gform-settings-panel gform-settings-panel--with-title gform-settings-panel--full">
				<legend className="gform-settings-panel__title gform-settings-panel__title--header">
					{__('Import Strategy', 'gp-conditional-pricing')}
				</legend>
				<div className="gform-settings-panel__content">
					<ul className="gpcp-importer-options gpcp-importer-fields">
						<li>
							<fieldset>
								<div className="gpcp-importer-option">
									<input
										type="radio"
										name="gpcp_import_type"
										value="replace_all"
										id={replaceAllId}
										checked={
											importStrategy === 'replace_all'
										}
										onChange={handleImportStrategyChange}
									/>
									&nbsp;
									{/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
									<label
										htmlFor={replaceAllId}
										dangerouslySetInnerHTML={{
											__html: __(
												'<strong>Replace All</strong> Replace <strong>ALL</strong> existing pricing rules with imported pricing rules.',
												'gp-conditional-pricing'
											),
										}}
									/>
								</div>
								<div className="gpcp-importer-option">
									<input
										type="radio"
										name="gpcp_import_type"
										value="replace_matching"
										id={replaceMatchingId}
										checked={
											importStrategy ===
											'replace_matching'
										}
										onChange={handleImportStrategyChange}
									/>
									&nbsp;
									{/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
									<label
										htmlFor={replaceMatchingId}
										dangerouslySetInnerHTML={{
											__html: __(
												'<strong>Replace Matching</strong> Replace existing pricing rules only for matching products with pricing rules in this import.',
												'gp-conditional-pricing'
											),
										}}
									/>
								</div>
								<div className="gpcp-importer-option">
									<input
										type="radio"
										name="gpcp_import_type"
										value="append"
										id={appendId}
										checked={importStrategy === 'append'}
										onChange={handleImportStrategyChange}
									/>
									&nbsp;
									{/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
									<label
										htmlFor={appendId}
										dangerouslySetInnerHTML={{
											__html: __(
												'<strong>Append</strong> Append imported pricing rules with existing pricing rules.',
												'gp-conditional-pricing'
											),
										}}
									/>
								</div>
							</fieldset>
						</li>
					</ul>
				</div>
			</fieldset>

			<div className="gwcp-import-file-form-buttons">
				<button
					type="submit"
					id="gwcp-pricing-level-import-confirm"
					className="primary button large"
					disabled={importButtonDisabled}
				>
					{__('Import Pricing Levels', 'gp-conditional-pricing')}
					&nbsp;→
				</button>
				<button
					type="button"
					id="gwcp-pricing-level-import-cancel"
					className="submitdelete deletion"
					onClick={(event: React.MouseEvent<HTMLButtonElement>) =>
						setActiveView('pricing-rules')
					}
				>
					{__('Cancel', 'gp-conditional-pricing')}
				</button>
			</div>
		</form>
	);
}
