/**
 * External dependencies
 */
import * as Ariakit from '@ariakit/react';
import { css, keyframes } from '@emotion/react';
import styled from '@emotion/styled';
/**
 * Internal dependencies
 */
import { COLORS, CONFIG } from '../utils';
import { space } from '../utils/space';
import { chevronIconSize } from '../select-control/styles/select-control-styles';
import { fontSizeStyles } from '../input-control/styles/input-control-styles';
import { DROPDOWN_MOTION_CSS } from '../utils/style-mixins';
import type { CustomSelectButtonSize } from './types';

const INLINE_PADDING = {
	compact: CONFIG.controlPaddingXSmall,
	small: CONFIG.controlPaddingXSmall,
	default: CONFIG.controlPaddingX,
};

const getSelectSize = (
	size: NonNullable< CustomSelectButtonSize[ 'size' ] >,
	heightProperty: 'minHeight' | 'height'
) => {
	const sizes = {
		compact: {
			[ heightProperty ]: 32,
			paddingInlineStart: INLINE_PADDING.compact,
			paddingInlineEnd: INLINE_PADDING.compact + chevronIconSize,
		},
		default: {
			[ heightProperty ]: 40,
			paddingInlineStart: INLINE_PADDING.default,
			paddingInlineEnd: INLINE_PADDING.default + chevronIconSize,
		},
		small: {
			[ heightProperty ]: 24,
			paddingInlineStart: INLINE_PADDING.small,
			paddingInlineEnd: INLINE_PADDING.small + chevronIconSize,
		},
	};

	return sizes[ size ] || sizes.default;
};

const getSelectItemSize = (
	size: NonNullable< CustomSelectButtonSize[ 'size' ] >
) => {
	// Used to visually align the checkmark with the chevron
	const checkmarkCorrection = 6;
	const sizes = {
		compact: {
			paddingInlineStart: INLINE_PADDING.compact,
			paddingInlineEnd: INLINE_PADDING.compact - checkmarkCorrection,
		},
		default: {
			paddingInlineStart: INLINE_PADDING.default,
			paddingInlineEnd: INLINE_PADDING.default - checkmarkCorrection,
		},
		small: {
			paddingInlineStart: INLINE_PADDING.small,
			paddingInlineEnd: INLINE_PADDING.small - checkmarkCorrection,
		},
	};

	return sizes[ size ] || sizes.default;
};

export const Select = styled( Ariakit.Select, {
	// Do not forward `hasCustomRenderProp` to the underlying Ariakit.Select component
	shouldForwardProp: ( prop ) => prop !== 'hasCustomRenderProp',
} )(
	( {
		size,
		hasCustomRenderProp,
	}: {
		size: NonNullable< CustomSelectButtonSize[ 'size' ] >;
		hasCustomRenderProp: boolean;
	} ) => css`
		display: block;
		background-color: ${ COLORS.theme.background };
		border: none;
		color: ${ COLORS.theme.foreground };
		cursor: pointer;
		font-family: inherit;
		text-align: start;
		user-select: none;
		width: 100%;

		&[data-focus-visible] {
			outline: none; // handled by InputBase component
		}

		${ getSelectSize( size, hasCustomRenderProp ? 'minHeight' : 'height' ) }
		${ ! hasCustomRenderProp && truncateStyles }
		${ fontSizeStyles( { inputSize: size } ) }
	`
);

const slideDown = keyframes( {
	'0%': { transform: `translateY(-${ DROPDOWN_MOTION_CSS.SLIDE_DISTANCE })` },
	'100%': { transform: 'translateY(0)' },
} );

const fadeIn = keyframes( {
	'0%': { opacity: 0 },
	'100%': { opacity: 1 },
} );

export const SelectPopover = styled( Ariakit.SelectPopover )`
	display: flex;
	flex-direction: column;

	background-color: ${ COLORS.theme.background };
	border-radius: ${ CONFIG.radiusSmall };
	border: 1px solid ${ COLORS.theme.foreground };
	box-shadow: ${ CONFIG.elevationMedium };

	/* z-index(".components-popover") */
	z-index: 1000000;

	max-height: min( var( --popover-available-height, 400px ), 400px );
	overflow: auto;
	overscroll-behavior: contain;

	/* The smallest size without overflowing the container. */
	min-width: min-content;

	/* Animation */
	&[data-open] {
		@media not ( prefers-reduced-motion ) {
			animation-name: ${ slideDown }, ${ fadeIn };
			animation-duration: ${ DROPDOWN_MOTION_CSS.SLIDE_DURATION },
				${ DROPDOWN_MOTION_CSS.FADE_DURATION };
			animation-timing-function: ${ DROPDOWN_MOTION_CSS.SLIDE_EASING },
				${ DROPDOWN_MOTION_CSS.FADE_EASING };
			will-change: transform, opacity;
		}
	}

	&[data-focus-visible] {
		/* The outline will be on the trigger, rather than the popover. */
		outline: none;
	}
`;

export const SelectItem = styled( Ariakit.SelectItem )(
	( {
		size,
	}: {
		size: NonNullable< CustomSelectButtonSize[ 'size' ] >;
	} ) => css`
		cursor: default;
		display: flex;
		align-items: center;
		justify-content: space-between;
		font-size: ${ CONFIG.fontSize };
		// TODO: reassess line-height for non-legacy v2
		line-height: 28px;
		padding-block: ${ space( 2 ) };
		scroll-margin: ${ space( 1 ) };
		user-select: none;

		&[aria-disabled='true'] {
			cursor: not-allowed;
		}

		&[data-active-item] {
			background-color: ${ COLORS.theme.gray[ 300 ] };
		}

		${ getSelectItemSize( size ) }
	`
);

const truncateStyles = css`
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
`;

export const SelectedExperimentalHintWrapper = styled.div`
	${ truncateStyles }
`;

export const SelectedExperimentalHintItem = styled.span`
	color: ${ COLORS.theme.gray[ 600 ] };
	margin-inline-start: ${ space( 2 ) };
`;

export const WithHintItemWrapper = styled.div`
	display: flex;
	justify-content: space-between;
	align-items: center;
	flex-wrap: wrap;
	flex: 1;
	column-gap: ${ space( 4 ) };
`;

export const WithHintItemHint = styled.span`
	color: ${ COLORS.theme.gray[ 600 ] };
	text-align: initial;
	line-height: ${ CONFIG.fontLineHeightBase };
	padding-inline-end: ${ space( 1 ) };
	margin-block: ${ space( 1 ) };
`;

export const SelectedItemCheck = styled( Ariakit.SelectItemCheck )`
	display: flex;
	align-items: center;
	margin-inline-start: ${ space( 2 ) };
	fill: currentColor;

	// Keep the checkmark vertically aligned at the top. Since the item text has a
	// 28px line height and the checkmark is 24px tall, a (28-24)/2 = 2px margin
	// is applied to keep the correct alignment between the text and the checkmark.
	align-self: start;
	margin-block-start: 2px;

	// Since the checkmark's dimensions are applied with 'em' units, setting a
	// font size of 0 allows the space reserved for the checkmark to collapse for
	// items that are not selected or that don't have an associated item hint.
	font-size: 0;
	${ WithHintItemWrapper } ~ &,
	&:not(:empty) {
		font-size: 24px; // Size of checkmark icon
	}
`;
