/**
 * External dependencies
 */
import { css, SerializedStyles } from '@emotion/react';
import styled from '@emotion/styled';
// eslint-disable-next-line no-restricted-imports
import type { CSSProperties, ReactNode } from 'react';

/**
 * Internal dependencies
 */
import type { GeChiUIComponentProps } from '../../ui/context';
import { Flex, FlexItem } from '../../flex';
import { Text } from '../../text';
import { COLORS, rtl } from '../../utils';
import type { LabelPosition } from '../types';

type ContainerProps = {
	disabled?: boolean;
	hideLabel?: boolean;
	__unstableInputWidth?: CSSProperties[ 'width' ];
	labelPosition?: LabelPosition;
};

type RootProps = {
	isFocused?: boolean;
	labelPosition?: LabelPosition;
};

const rootFocusedStyles = ( { isFocused }: RootProps ) => {
	if ( ! isFocused ) return '';

	return css( { zIndex: 1 } );
};

const rootLabelPositionStyles = ( { labelPosition }: RootProps ) => {
	switch ( labelPosition ) {
		case 'top':
			return css`
				align-items: flex-start;
				flex-direction: column;
			`;
		case 'bottom':
			return css`
				align-items: flex-start;
				flex-direction: column-reverse;
			`;
		case 'edge':
			return css`
				justify-content: space-between;
			`;
		default:
			return '';
	}
};

export const Root = styled( Flex )< RootProps >`
	position: relative;
	border-radius: 2px;
	padding-top: 0;
	${ rootFocusedStyles }
	${ rootLabelPositionStyles }
`;

const containerDisabledStyles = ( { disabled }: ContainerProps ) => {
	const backgroundColor = disabled
		? COLORS.ui.backgroundDisabled
		: COLORS.ui.background;

	return css( { backgroundColor } );
};

// Normalizes the margins from the <Flex /> (components/ui/flex/) container.
const containerMarginStyles = ( { hideLabel }: ContainerProps ) => {
	return hideLabel ? css( { margin: '0 !important' } ) : null;
};

const containerWidthStyles = ( {
	__unstableInputWidth,
	labelPosition,
}: ContainerProps ) => {
	if ( ! __unstableInputWidth ) return css( { width: '100%' } );

	if ( labelPosition === 'side' ) return '';

	if ( labelPosition === 'edge' ) {
		return css( {
			flex: `0 0 ${ __unstableInputWidth }`,
		} );
	}

	return css( { width: __unstableInputWidth } );
};

export const Container = styled.div< ContainerProps >`
	align-items: center;
	box-sizing: border-box;
	border-radius: inherit;
	display: flex;
	flex: 1;
	position: relative;

	${ containerDisabledStyles }
	${ containerMarginStyles }
	${ containerWidthStyles }
`;

type Size = 'default' | 'small';

type InputProps = {
	disabled?: boolean;
	inputSize?: Size;
	isDragging?: boolean;
	dragCursor?: CSSProperties[ 'cursor' ];
};

const disabledStyles = ( { disabled }: InputProps ) => {
	if ( ! disabled ) return '';

	return css( {
		color: COLORS.ui.textDisabled,
	} );
};

const fontSizeStyles = ( { inputSize: size }: InputProps ) => {
	const sizes = {
		default: '13px',
		small: '11px',
	};

	const fontSize = sizes[ size as Size ] || sizes.default;
	const fontSizeMobile = '16px';

	if ( ! fontSize ) return '';

	return css`
		font-size: ${ fontSizeMobile };

		@media ( min-width: 600px ) {
			font-size: ${ fontSize };
		}
	`;
};

const sizeStyles = ( { inputSize: size }: InputProps ) => {
	const sizes = {
		default: {
			height: 30,
			lineHeight: 1,
			minHeight: 30,
		},
		small: {
			height: 24,
			lineHeight: 1,
			minHeight: 24,
		},
	};

	const style = sizes[ size as Size ] || sizes.default;

	return css( style );
};

const dragStyles = ( { isDragging, dragCursor }: InputProps ) => {
	let defaultArrowStyles: SerializedStyles | undefined;
	let activeDragCursorStyles: SerializedStyles | undefined;

	if ( isDragging ) {
		defaultArrowStyles = css`
			cursor: ${ dragCursor };
			user-select: none;

			&::-webkit-outer-spin-button,
			&::-webkit-inner-spin-button {
				-webkit-appearance: none !important;
				margin: 0 !important;
			}
		`;
	}

	if ( isDragging && dragCursor ) {
		activeDragCursorStyles = css`
			&:active {
				cursor: ${ dragCursor };
			}
		`;
	}

	return css`
		${ defaultArrowStyles }
		${ activeDragCursorStyles }
	`;
};

// TODO: Resolve need to use &&& to increase specificity
// https://github.com/GeChiUI/gutenberg/issues/18483

export const Input = styled.input< InputProps >`
	&&& {
		background-color: transparent;
		box-sizing: border-box;
		border: none;
		box-shadow: none !important;
		color: ${ COLORS.black };
		display: block;
		margin: 0;
		outline: none;
		padding-left: 8px;
		padding-right: 8px;
		width: 100%;

		${ dragStyles }
		${ disabledStyles }
		${ fontSizeStyles }
		${ sizeStyles }

		&::-webkit-input-placeholder {
			line-height: normal;
		}
	}
`;

const labelPadding = ( {
	labelPosition,
}: {
	labelPosition?: LabelPosition;
} ) => {
	let paddingBottom = 4;

	if ( labelPosition === 'edge' || labelPosition === 'side' ) {
		paddingBottom = 0;
	}

	return css( { paddingTop: 0, paddingBottom } );
};

const BaseLabel = styled( Text )< { labelPosition?: LabelPosition } >`
	&&& {
		box-sizing: border-box;
		color: currentColor;
		display: block;
		margin: 0;
		max-width: 100%;
		z-index: 1;

		${ labelPadding }
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
	}
`;

export const Label = (
	props: GeChiUIComponentProps<
		{ labelPosition?: LabelPosition; children: ReactNode },
		'label',
		false
	>
) => <BaseLabel { ...props } as="label" />;

export const LabelWrapper = styled( FlexItem )`
	max-width: calc( 100% - 10px );
`;

type BackdropProps = {
	disabled?: boolean;
	isFocused?: boolean;
};

const backdropFocusedStyles = ( {
	disabled,
	isFocused,
}: BackdropProps ): SerializedStyles => {
	let borderColor = isFocused ? COLORS.ui.borderFocus : COLORS.ui.border;

	let boxShadow;

	if ( isFocused ) {
		boxShadow = `0 0 0 1px ${ COLORS.ui.borderFocus } inset`;
	}

	if ( disabled ) {
		borderColor = COLORS.ui.borderDisabled;
	}

	return css( {
		boxShadow,
		borderColor,
		borderStyle: 'solid',
		borderWidth: 1,
	} );
};

export const BackdropUI = styled.div< BackdropProps >`
	&&& {
		box-sizing: border-box;
		border-radius: inherit;
		bottom: 0;
		left: 0;
		margin: 0;
		padding: 0;
		pointer-events: none;
		position: absolute;
		right: 0;
		top: 0;

		${ backdropFocusedStyles }
		${ rtl( { paddingLeft: 2 } ) }
	}
`;

export const Prefix = styled.span`
	box-sizing: border-box;
	display: block;
`;

export const Suffix = styled.span`
	box-sizing: border-box;
	display: block;
`;
