import { useCallback, useEffect } from 'react';
import { Stack, TextField, Checkbox, Typography, FormControlLabel, Box } from '@mui/material';

// WordPress admin form rules override MUI's invisible input size and margin.
// Keep the input over the whole visible checkbox so clicks reach onChange.
const COMPANION_CHECKBOX_SX = {
	'& input[type="checkbox"]': { margin: 0, width: '100%', height: '100%' },
};

const MARKUP_HELP = 'Markup (e.g Currency 1.00 or percentage 5%)';
const LABEL_HELP = 'Service name displays by default. Enter an alternative if you prefer something different';
const LABEL_MAX = 50;
const MARKUP_MAX = 7;
// Same shape the handling fee accepts: a currency amount or a percentage, either of which may be negative.
const MARKUP_PATTERN = /^-?[0-9.]*%?$/;

/**
 * A provider's service checklist for one direction.
 *
 * Every service is a checkbox with a markup. Providers whose services can also be renamed pass
 * showLabelAs, which adds a "Label as" field per service and stacks the row so the two inputs sit
 * under the service name rather than beside it.
 *
 * A companion column ({ type, title, selectAll, services }) adds a second tick per row, stored
 * under services[companion.type]. Its title and Select all sit on the same rows as this list's
 * title and Select all; each tick sits on the line of that service's own checkbox (the Label as
 * line, or the Markup line without Label as). Rows without a companion service stay blank.
 */
const ProviderServices = ({
	services,
	service_type,
	selectAll,
	state,
	setQuoteSettingsState,
	selectAllText = 'Select all',
	showTitle = true,
	showLabelAs = false,
	companion = null,
	title,
}) => {
	const type = service_type.toLowerCase();
	const companionType = companion?.type;
	const companionServices = companion?.services;

	useEffect(() => {
		setQuoteSettingsState(prevState => {
			const servicesInitialState = {};
			const markupsInitialState = {};
			const labelsInitialState = {};
			const companionInitialState = {};

			for (let s of services) {
				servicesInitialState[s.index] = false;
				if (s.markup) markupsInitialState[s.markup] = '';
				if (s.labelAs) labelsInitialState[s.labelAs] = '';
			}

			for (let s of companionServices || []) {
				companionInitialState[s.index] = false;
			}

			return {
				...prevState,
				services: {
					...prevState?.services,
					[type]: {
						...servicesInitialState,
						...prevState?.services?.[type],
					},
					...(companionType && {
						[companionType]: {
							...companionInitialState,
							...prevState?.services?.[companionType],
						},
					}),
				},
				markups: {
					...markupsInitialState,
					...prevState?.markups,
				},
				labels_as: {
					...labelsInitialState,
					...prevState?.labels_as,
				},
			};
		});
	}, [type, services, companionType, companionServices, setQuoteSettingsState]);

	const setBucket = useCallback(
		(bucket, name, val) => {
			setQuoteSettingsState(prevState => ({
				...prevState,
				[bucket]: { ...prevState?.[bucket], [name]: val },
			}));
		},
		[setQuoteSettingsState]
	);

	const toggleIn = useCallback(
		(bucket, selectAllKey, list, name, val) => {
			const othersChecked = list
				.filter(s => s.index !== name)
				.every(s => state?.services?.[bucket]?.[s.index]);

			setQuoteSettingsState(prevState => ({
				...prevState,
				[selectAllKey]: othersChecked && val,
				services: {
					...prevState?.services,
					[bucket]: { ...prevState?.services?.[bucket], [name]: val },
				},
			}));
		},
		[setQuoteSettingsState, state]
	);

	const selectAllIn = useCallback(
		(bucket, selectAllKey, list, checked) => {
			setQuoteSettingsState(prevState => {
				const updated = { ...prevState?.services?.[bucket] };
				list.forEach(service => {
					updated[service.index] = checked;
				});

				return {
					...prevState,
					[selectAllKey]: checked,
					services: { ...prevState?.services, [bucket]: updated },
				};
			});
		},
		[setQuoteSettingsState]
	);

	const toggleService = (name, val) => toggleIn(type, selectAll, services, name, val);
	const selectAllServices = checked => selectAllIn(type, selectAll, services, checked);

	const withCompanion = (row, cell, key) => {
		if (!companion) return row;

		return (
			<Box key={key} sx={{ display: 'flex', alignItems: 'flex-start' }}>
				<Box sx={{ flex: 1, minWidth: 0 }}>{row}</Box>
				<Box sx={{ flex: 1, display: 'flex', justifyContent: 'center' }}>{cell}</Box>
			</Box>
		);
	};

	const line = (content, cell = null) => {
		if (!companion) return content;

		return (
			<Box sx={{ display: 'flex', alignItems: 'center' }}>
				<Box sx={{ flex: 1, minWidth: 0 }}>
					<Box sx={{ width: '95%' }}>{content}</Box>
				</Box>
				<Box sx={{ flex: 1, display: 'flex', justifyContent: 'center' }}>{cell}</Box>
			</Box>
		);
	};

	const companionTick = ({ label, index }) => {
		if (!companionServices?.some(s => s.index === index)) return null;

		return (
			<Checkbox
				sx={{ ...COMPANION_CHECKBOX_SX, p: 0 }}
				checked={!!state?.services?.[companionType]?.[index]}
				onChange={e => toggleIn(companionType, companion.selectAll, companionServices, index, e.target.checked)}
				title={label}
				inputProps={{ 'aria-label': `${companion.title}: ${label}` }}
			/>
		);
	};

	const serviceBlock = ({ label, index, markup, labelAs }, cell = null) => {
		const blockWidth = companion ? '100%' : '95%';
		const checkbox = (
			<FormControlLabel
				control={
					<Checkbox
						checked={(state?.services && state?.services?.[type]?.[index]) || false}
						onChange={e => toggleService(index, e.target.checked)}
						title={label}
						inputProps={{ 'aria-label': `${title || service_type}: ${label}` }}
					/>
				}
			/>
		);

		const help = (text, component = 'p') => {
			const caption = (
				<Typography variant='caption' color='text.secondary' component={component}>
					{text}
				</Typography>
			);

			return (
				<Box sx={{ display: 'flex', gap: 2 }}>
					<Box sx={{ flex: 1, minWidth: 0 }}>{caption}</Box>
					<Box sx={{ visibility: 'hidden', height: 0, overflow: 'hidden' }} aria-hidden='true'>
						{checkbox}
					</Box>
				</Box>
			);
		};

		if (!showLabelAs) {
			return (
				<Box key={index} mb={2} sx={{ width: blockWidth }}>
					{line(<Typography variant='body1'>{label}</Typography>)}

					{line(
						<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
							<TextField
								fullWidth
								title={MARKUP_HELP}
								placeholder='Markup'
								inputProps={{ maxLength: MARKUP_MAX }}
								value={(state?.markups && state?.markups[markup]) || ''}
								onChange={e =>
									MARKUP_PATTERN.test(e.target.value) &&
									setBucket('markups', markup, e.target.value)
								}
							/>
							{checkbox}
						</Box>,
						cell
					)}

					{line(help(MARKUP_HELP, 'span'))}
				</Box>
			);
		}

		return (
			<Box key={index} mb={2} sx={{ width: blockWidth }}>
				{line(<Typography variant='body1'>{label}</Typography>)}

				{line(
					<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
						<TextField
							fullWidth
							size='small'
							title='Label as'
							placeholder='Label as'
							inputProps={{ maxLength: LABEL_MAX }}
							value={(state?.labels_as && state?.labels_as[labelAs]) || ''}
							onChange={e => setBucket('labels_as', labelAs, e.target.value)}
						/>
						{checkbox}
					</Box>,
					cell
				)}
				{line(help(LABEL_HELP))}

				{line(
					<Box sx={{ display: 'flex', alignItems: 'center', gap: 2, mt: 1 }}>
						<TextField
							fullWidth
							size='small'
							title={MARKUP_HELP}
							placeholder='Markup'
							inputProps={{ maxLength: MARKUP_MAX }}
							value={(state?.markups && state?.markups[markup]) || ''}
							onChange={e =>
								MARKUP_PATTERN.test(e.target.value) &&
								setBucket('markups', markup, e.target.value)
							}
						/>
						<Box sx={{ visibility: 'hidden' }}>{checkbox}</Box>
					</Box>
				)}
				{line(help(MARKUP_HELP))}
			</Box>
		);
	};

	const serviceRow = service => serviceBlock(service, companion && companionTick(service));

	return (
		<>
			<Stack>
				{showTitle &&
					withCompanion(
						<Stack align='center' my={3} sx={{ width: '95%' }}>
							<Typography variant='h6' component='h6' fontSize='1rem'>
								{title || `${service_type} services`}
							</Typography>
						</Stack>,
						<Stack align='center' my={3}>
							<Typography variant='h6' component='h6' fontSize='1rem'>
								{companion?.title}
							</Typography>
						</Stack>,
						'title'
					)}

				{withCompanion(
					<Stack
						direction='row'
						alignItems='center'
						justifyContent='space-between'
						sx={{ width: '95%' }}>
						<Typography variant='body1'>{selectAllText}</Typography>

						<FormControlLabel
							control={
								<Checkbox
									checked={!!state[selectAll]}
									onChange={e => selectAllServices(e.target.checked)}
									title={selectAllText}
									inputProps={{ 'aria-label': `${title || service_type}: ${selectAllText}` }}
								/>
							}
						/>
					</Stack>,
					companion && (
						<Checkbox
							sx={COMPANION_CHECKBOX_SX}
							checked={!!state[companion.selectAll]}
							onChange={e =>
								selectAllIn(companionType, companion.selectAll, companionServices, e.target.checked)
							}
							title={selectAllText}
							inputProps={{ 'aria-label': `${companion.title}: ${selectAllText}` }}
						/>
					),
					'select-all'
				)}
			</Stack>

			{services.map(serviceRow)}
		</>
	);
};

export default ProviderServices;
