import { useEffect } from 'react';
import { useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import type {
	PricingLevel,
	PricingCondition,
	Operators,
	LogicType,
	ActionType,
} from '../../typings/types';
import { useBoundStore } from '../../store/store';
import { numberToDisplayPrice } from '../../utilities';
import { __, sprintf } from '@wordpress/i18n';

const { gp_conditional_pricing_form_settings_strings: strings } = window;

function getCustomRuleFieldLabel(fieldAndInputId: string): string {
	if (typeof window.GetRuleFields !== 'function') {
		return '';
	}

	const ruleFieldMarkup = window.GetRuleFields(
		'pricing_level',
		0,
		fieldAndInputId
	);
	const matchingOption = jQuery(ruleFieldMarkup)
		.find('option')
		.filter((_, option) => String(option.value) === String(fieldAndInputId))
		.first();

	return matchingOption.text() ?? '';
}

function mapFieldIdToDisplayLabel(fieldAndInputId: string) {
	const quantityFieldPrefix = 'quantity_';
	const isQuantityField = fieldAndInputId.startsWith(quantityFieldPrefix);
	if (isQuantityField) {
		// trim of quantity_ prefix
		fieldAndInputId = fieldAndInputId.slice(quantityFieldPrefix.length);
	}

	// eslint-disable-next-line @wordpress/no-unused-vars-before-return
	const [fieldId] = fieldAndInputId.split('.');

	const field = window.form.fields.find(({ id }) => {
		return String(id) === String(fieldId);
	});

	if (!field) {
		return getCustomRuleFieldLabel(fieldAndInputId);
	}

	let label = field.label ?? '';

	if (field.inputs) {
		const input = field.inputs.find(({ id }: GFFieldInput) => {
			return String(id) === String(fieldAndInputId);
		});

		if (input) {
			label = `${label} (${input.label})`;
		}
	}

	if (isQuantityField) {
		label = `${label} (Quantity)`;
	}

	return label;
}

function mapOperatorToDisplayLabel(operator: Operators) {
	return strings.operator_labels[operator];
}

function showPricingLevelRuleFields() {
	/**
	 * The GravityForms conditional logic ToggleConditionalLogic function
	 * attaches the appropriate UI inside of `#gwcp-pricing-level-editor`.
	 * We render that below and then but then wait until the very next tick
	 * to call ToggleConditionalLogic to ensure that the DOM is ready.
	 */
	setTimeout(() => {
		window.ToggleConditionalLogic(true, 'pricing_level');
		/**
		 * Add GF 2.5 class for conditional logic since we're not using the
		 * new GF 2.5 settings API [yet].
		 */
		jQuery('#pricing_level_conditional_logic_container').addClass(
			'gform-settings-field__conditional-logic'
		);
	}, 0);
}

interface PricingLevelProps {
	pricingLevel: PricingLevel;
}

export function PricingLevel(props: PricingLevelProps) {
	const { pricingLevel } = props;

	const {
		activePricingLevelId,
		setActivePricingLevel,
		updateActiveProductPricingLevel,
		deleteActiveProductPricingLevel,
	} = useBoundStore((state) => ({
		activePricingLevelId: state.activePricingLevelId,
		setActivePricingLevel: state.setActivePricingLevel,
		getActivePricingLevel: state.getActivePricingLevel,
		updateActiveProductPricingLevel: state.updateActiveProductPricingLevel,
		deleteActiveProductPricingLevel: state.deleteActiveProductPricingLevel,
	}));

	const { attributes, listeners, setNodeRef, transform, transition } =
		useSortable({
			id: pricingLevel.uuid,
			disabled: activePricingLevelId !== null,
		});

	const style = {
		transform: CSS.Transform.toString(transform),
		transition,
	};

	const isInEditMode = activePricingLevelId === pricingLevel.uuid;

	useEffect(() => {
		// Handles displaying the pricing level editor for a newly added product.
		if (
			activePricingLevelId === pricingLevel.uuid &&
			// fieldId will be 0 for a newly created pricing level.
			Number(pricingLevel.conditionalLogic?.rules[0]?.fieldId) === 0
		) {
			showPricingLevelRuleFields();
		}
	}, [pricingLevel, activePricingLevelId]);

	const handleEditClick = () => {
		setActivePricingLevel(pricingLevel.uuid);
		showPricingLevelRuleFields();
	};

	const getPricingLevelStateFromDOM = () => {
		const selects = jQuery(
			'#pricing_level_conditional_logic_container .gf_conditional_logic_rules_container'
		).toArray();

		const rules: PricingCondition[] = selects.map((_, i) => {
			const ruleField = jQuery(`#pricing_level_rule_field_${i}`)
				.find('option:selected')
				.val();

			const ruleOperator = jQuery(`#pricing_level_rule_operator_${i}`)
				.find('option:selected')
				.val() as Operators;

			let ruleValue;

			const ruleValueInputType = jQuery(
				`#pricing_level_rule_value_${i}`
			).attr('type');

			switch (ruleValueInputType) {
				case 'number':
					ruleValue = jQuery(`#pricing_level_rule_value_${i}`).val();
					break;

				case 'text':
					ruleValue = jQuery(`#pricing_level_rule_value_${i}`).val();
					break;

				default:
					ruleValue = jQuery(`#pricing_level_rule_value_${i}`)
						.find('option:selected')
						.val();
			}

			return {
				fieldId: ruleField as string,
				operator: ruleOperator as Operators,
				value: ruleValue as string,
			};
		});

		const price = jQuery('#gwcp-pricing-level-price').val() as string;
		const logicType = jQuery('#pricing_level_logic_type')
			.find('option:selected')
			.val() as LogicType;
		const actionType = jQuery('#pricing_level_action_type')
			.find('option:selected')
			.val() as ActionType;

		const updatedPricingLevel: PricingLevel = {
			uuid: pricingLevel.uuid,
			price,
			productId: pricingLevel.productId,
			conditionalLogic: {
				actionType,
				logicType,
				rules,
			},
		};

		return updatedPricingLevel;
	};

	const handleSaveClick = () => {
		const updatedPricingLevel = getPricingLevelStateFromDOM();
		updateActiveProductPricingLevel(updatedPricingLevel);
		setActivePricingLevel(null);
	};

	const handleDeleteClick = () => {
		deleteActiveProductPricingLevel(pricingLevel.uuid);
		setActivePricingLevel(null);
	};

	if (isInEditMode) {
		return (
			<div
				id="gwcp-pricing-level-editor"
				className="panel-block-tabs__body--settings gform-settings-panel"
			>
				<input
					type="checkbox"
					id="pricing_level_conditional_logic"
					value="1"
					checked={true}
					readOnly={true}
				/>
				<div id="pricing_level_conditional_logic_container">
					{/* <!-- dynamically populated --> */}
				</div>
				<div className="gwcp-pricing-level-editor-actions submitbox">
					<button
						type="button"
						id="gwcp-pricing-level-editor-close"
						className="button"
						onClick={handleSaveClick}
					>
						{__('Done', 'gp-conditional-pricing')}
					</button>
					<button
						type="button"
						id="gwcp-pricing-level-editor-delete"
						className="submitdelete deletion"
						onClick={handleDeleteClick}
					>
						{__('Delete', 'gp-conditional-pricing')}
					</button>
				</div>
			</div>
		);
	}

	return (
		<div
			className="gwcp-pricing-level gform-settings-panel"
			ref={setNodeRef}
			style={style}
			{...attributes}
			{...listeners}
		>
			<p>
				<span
					dangerouslySetInnerHTML={{
						__html: sprintf(
							// translators: %1$s is the price, %2$s is the logic type (all or any)
							__(
								'This product costs <strong>%1$s</strong> if <strong>%2$s</strong> of the following match:',
								'gp-conditional-pricing'
							),
							numberToDisplayPrice(pricingLevel.price),
							pricingLevel.conditionalLogic?.logicType
						),
					}}
				/>
				<button
					type="button"
					className="gwcp-edit-pricing-level"
					onClick={handleEditClick}
				>
					{__('Edit', 'gp-conditional-pricing')}
				</button>
			</p>
			<ul>
				{pricingLevel.conditionalLogic?.rules?.map((rule, i) => {
					const connector =
						pricingLevel.conditionalLogic.logicType === 'all'
							? 'and'
							: 'or';
					const fieldName = mapFieldIdToDisplayLabel(rule.fieldId);
					const operator = mapOperatorToDisplayLabel(rule.operator);

					return (
						<li key={`${rule.fieldId}_${rule.value}_${i}`}>
							<strong>{fieldName}</strong> {operator}{' '}
							{rule.value === '' ? (
								<strong>empty</strong>
							) : (
								<span>&quot;{rule.value}&quot;</span>
							)}
							{i <
								pricingLevel.conditionalLogic?.rules?.length -
									1 && (
								<i style={{ color: '#999' }}> {connector}</i>
							)}
						</li>
					);
				})}
			</ul>
		</div>
	);
}
