import React, { JSX } from 'react';
import { __experimentalHeading as Heading, Flex } from '@wordpress/components';
import { isEmpty, map } from 'lodash';
import { __ } from '@wordpress/i18n';
import { Form } from '@woocommerce/components';
import { useSelect } from '@wordpress/data';
import { CustomsState } from 'types';
import { useLabelPurchaseContext } from 'context/label-purchase';
import { CustomsForm } from './customs-form';
import {
	createLocalErrors,
	validateContentTypes,
	validateItems,
	validateITN,
	validateRestrictionType,
} from './validators';
import { addressStore } from 'data/address';
import { getCountryName } from 'utils';

export const Customs = (): JSX.Element => {
	const {
		customs: { getCustomsState, setCustomsState, setErrors },
		essentialDetails: { setCustomsCompleted },
		shipment: { getShipmentOrigin },
	} = useLabelPurchaseContext();

	const { country } = useSelect(
		( select ) => select( addressStore ).getOrderDestination(),
		[]
	);

	const destinationContext = {
		country,
		countryName: getCountryName()( country ),
		originCountry: getShipmentOrigin()?.country,
	};

	const initialValues = getCustomsState();

	return (
		<Flex className="label-purchase-customs" direction="column">
			<Heading level={ 3 }>
				{ __( 'Customs', 'woocommerce-shipping' ) }
			</Heading>
			{ initialValues && (
				<Form< CustomsState >
					// Update the form if length of items changes as a result of shipment split
					key={ map( initialValues.items, 'id' ).join( '--' ) }
					onSubmit={ ( values ) => {
						setCustomsState( values );
					} }
					initialValues={ initialValues }
					validate={ ( values ) => {
						const errors = [
							{
								values,
								errors: createLocalErrors( values.items ),
							},
						]
							.map( validateContentTypes )
							.map( validateRestrictionType )
							.map( validateITN( destinationContext ) )
							.map(
								validateItems( destinationContext )
							)[ 0 ].errors;

						/**
						 * If there is no error, `errors.items` will still have 1 item that's an empty obj. For example: errors.items[0] = {}
						 * If there are errors, `errors.items` will have 1+ items that's an array of error messages, and `errors` can
						 * contain other keys. For example:
						 *
						 *   errors = {
						 *     items[0] = {
						 *         "weight": "This field is required",
						 *         "price": "This field is required"
						 *       },
						 *     itn: "error message",
						 *     contentExplanation: "error message"
						 *   }
						 *
						 * Every time validation runs, check again and mark the customs essential details as done if and only if there is no error.
						 */
						if (
							errors?.items[ 0 ] &&
							Object.keys( errors ).length <= 1 &&
							errors?.items.every( isEmpty )
						) {
							setCustomsCompleted( true );
						} else {
							setCustomsCompleted( false );
						}

						setErrors( errors );
						return errors;
					} }
					onChange={ ( _, values ) => {
						setCustomsState( values );
					} }
				>
					<CustomsForm />
				</Form>
			) }
		</Flex>
	);
};