import './AddressForm.scss'
import AddressModal from './AddressModal'
import TextField from './../personalInfo/TextField'
import Dropdown from './Dropdown'
import { useFormik } from 'formik'
import { useMemo } from 'react'
import { getAddressTypeLabel } from './addressUtils'
import { t } from '$themelocalization'

const API_KEY_MAP = {
	'CountryID': 'Country',
	'StateID': 'State',
}

const mapItemsToDropdownFormat = (items) => {
	return items.map((item) => ({
		id: String(item.ID),
		name: item.Name,
		value: String(item.ID),
	}))
}

const validateForm = (values, fields) => {
	const errors = {}


	fields.forEach((field) => {
		const value = values[field.Name]

		const isStateField = field.Name === 'StateID'
		const shouldTreatAsMandatory = field.IsMandatory || isStateField

		if (shouldTreatAsMandatory && !value) {
			errors[field.Name] = t('AddressForm.Validation_enter_required', { fieldLabel: field.DisplayName })
		}

		const fieldValidation = field.Validations.filter((validation) => validation.Type === 2)[0]


		if (fieldValidation?.RegularExpression && value) {
			const pattern = fieldValidation.RegularExpression
			const regex = new RegExp(pattern.replace(/^\/|\/$/g, ""))
			const validationError =
				!regex.test(value)
			if (validationError) {
				errors[field.Name] =
					fieldValidation.Message
			}
		}
	})

	return errors
}

const AddressForm = ({
	formFields = [],
	showModal,
	setShowModal,
	type,
	address = null,
	countries = [],
	states = [],
	onSubmit,
}) => {
	const [submitAttempted, setSubmitAttempted] = React.useState(false)
	const [serverError, setServerError] = React.useState(null)
	const title = getAddressTypeLabel(type)
	const isEditMode = Boolean(address)

	const countriesById = useMemo(
		() => new Map(countries.map(country => [String(country.ID), country])),
		[countries]
	)

	const statesByCountryId = useMemo(() => {
		return Object.entries(states || {}).reduce((acc, [countryId, stateList]) => {
			acc[String(countryId)] = new Map(
				(stateList || []).map((state) => [String(state.ID), state])
			)
			return acc
		}, {})
	}, [states])


	const getEmptyFormValuesForFields = (fields) => {
		return fields.reduce((acc, field) => {
			if (field.Name === 'CountryID') {
				acc[field.Name] = field.Options.length === 1 ? String(field.Options[0].Value) : null
				return acc
			}
			acc[field.Name] = field.Name === 'StateID' ? null : ''
			return acc
		}, {})
	}

	const mapAddressToFormValuesForFields = (address, fields) => {
		const mappedValues = {}

		for (const field of fields) {
			const addressKey = API_KEY_MAP[field.Name] || field.Name
			const value = address[addressKey]
			if (field.Name === 'CountryID' || field.Name === 'StateID') {
				mappedValues[field.Name] = value?.ID != null && value.SupportedInStore ? String(value.ID) : null
			} else {
				mappedValues[field.Name] = value || ''
			}
		}

		return { ...getEmptyFormValuesForFields(fields), ...mappedValues }
	}

	const formInitialValues = useMemo(() => {
		if (address) {
			return mapAddressToFormValuesForFields(address, formFields)
		}

		return getEmptyFormValuesForFields(formFields)
	}, [address, formFields])

	const validateFormWithStates = (values) => {
		const errors = validateForm(values, formFields)

		const selectedCountryId = values.CountryID || null
		const hasStatesForCountry = Boolean(
			selectedCountryId &&
			states?.[selectedCountryId] &&
			states[selectedCountryId].length > 0
		)

		if (!hasStatesForCountry && errors.StateID) {
			delete errors.StateID
		}

		return errors
	}

	const formik = useFormik({
		initialValues: formInitialValues,
		enableReinitialize: true,
		validate: validateFormWithStates,
		validateOnBlur: false,
		validateOnChange: false,
		onSubmit: async (values) => {
			const valuesWithLocation = { ...values }

			const selectedCountry = values.CountryID
				? countriesById.get(String(values.CountryID))
				: null

			if (selectedCountry) {
				valuesWithLocation.Country = {
					ID: selectedCountry.ID,
					Name: selectedCountry.Name,
					SupportedInStore: true,
				}
			}

			const statesMap = values.CountryID
				? statesByCountryId[String(values.CountryID)]
				: null

			const selectedState = values.StateID && statesMap
				? statesMap.get(String(values.StateID))
				: null

			if (selectedState) {
				valuesWithLocation.State = {
					ID: selectedState.ID,
					Name: selectedState.Name,
					SupportedInStore: true,
				}
			}

			try {
				await onSubmit?.(valuesWithLocation, isEditMode)
				setServerError(null)
				setShowModal(false)
				formik.resetForm()
			} catch (error) {
				const fieldLabel = formFields.find((f) => f.Name === 'Name')?.DisplayName || 'Name'
				setServerError({
					field: 'Name',
					message: t('AddressForm.Validation_already_exists', { fieldLabel })
				})
			}
		},
	})

	const clearFieldError = (name) => {
		if (formik.errors?.[name]) {
			const { [name]: _, ...rest } = formik.errors
			formik.setErrors(rest)
		}
	}

	const handleTextInput = (event) => {
		const { name, value } = event.target

		formik.setFieldValue(name, value, false)

		clearFieldError(name)

		if (serverError?.field === name) {
			setServerError(null)
		}
	}

	const countryItems = useMemo(
		() => mapItemsToDropdownFormat(countries),
		[countries]
	)

	const selectedCountryId = formik.values.CountryID || null
	const selectedStateId = formik.values.StateID || null

	const stateItems = useMemo(() => {
		if (!selectedCountryId || !states?.[selectedCountryId]) {
			return []
		}
		return mapItemsToDropdownFormat(states[selectedCountryId])
	}, [selectedCountryId, states])



	const handleCountryChange = (key) => {
		formik.setFieldValue('CountryID', key || null)
		formik.setFieldTouched('CountryID', false, false)
		formik.setFieldValue('StateID', null)
		clearFieldError('CountryID')
		clearFieldError('StateID')
	}

	const handleStateChange = (key) => {
		formik.setFieldValue('StateID', key || null)
		clearFieldError('StateID')
	}

	const handleCancel = () => {
		formik.resetForm()
		setServerError(null)
		setShowModal(false)
	}

	const handleSubmit = () => {
		setSubmitAttempted(true)
		const fieldsToTouch = Object.fromEntries(
			formFields.map(field => [field.Name, true])
		)
		formik.setTouched(fieldsToTouch)
		formik.submitForm()
	}

	const hasValidationErrors =
		(Object.keys(formik.errors).length > 0 &&
		Object.keys(formik.touched).length > 0) ||
		serverError !== null
	const shouldShowGlobalValidation = submitAttempted && hasValidationErrors
	const renderField = (field) => {
		const formError = formik.touched[field.Name] && formik.errors[field.Name]
		const fieldServerError = serverError?.field === field.Name ? serverError.message : null
		const error = formError || fieldServerError

		if (field.Name === 'CountryID') {
			return (
				<Dropdown
					key={field.Name}
					label={field.DisplayName}
					items={countryItems}
					placeholder={t('AddressForm.Placeholder.SelectCountry')}
					selectedKey={selectedCountryId}
					onChange={handleCountryChange}
					error={error}
					isRequired={field.IsMandatory}
				/>
			)
		}

		if (field.Name === 'StateID') {
			if (selectedCountryId && stateItems.length > 0) {
				return (
					<Dropdown
						key={field.Name}
						label={field.DisplayName}
						items={stateItems}
						placeholder={t('AddressForm.Placeholder.SelectState')}
						selectedKey={selectedStateId}
						onChange={handleStateChange}
						error={error}
						isRequired={true}
					/>
				)
			} else {
				return null
			}
		}

		return (
			<TextField
				key={field.Name}
				autoComplete='off'
				error={error}
				label={field.DisplayName}
				name={field.Name}
				onBlur={formik.handleBlur}
				onInput={handleTextInput}
				type='text'
				value={formik.values[field.Name] || ''}
				isRequired={field.IsMandatory}
				disabled={field.IsReadOnly}
			/>
		)
	}

	return (
		<AddressModal
			open={showModal}
			title={`${title} ${t('AddressForm.Address')}`}
			actionButtonText={t('AddressForm.Button.Save')}
			cancelButtonText={t('AddressForm.Button.Cancel')}
			onAction={handleSubmit}
			onCancel={handleCancel}
			hasValidationErrors={shouldShowGlobalValidation}
			onResetValidationError={() => {
				setSubmitAttempted(false)
			}}
			className={'address-form-modal'}
		>
			<div className='address-form-fields'>{formFields.map(renderField)}</div>
		</AddressModal>
	)
}

export default AddressForm
