import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { cloneElement, useEffect, forwardRef, useState, useRef, Children } from 'react';
import styled, { css } from 'styled-components';
import { rgba } from 'polished';
import { defaultThemeProp } from '../../theme';
import Flex from '../Flex';
import Actions from '../Actions';
import { useConsolidatedRef, useI18n, useLiveLog, useTestIds, useUID } from '../../hooks';
import Label, { StyledLabel } from '../Label';
import { calculateFontSize, getHoverColors, readableColor } from '../../styles';
import VisuallyHiddenText from '../VisuallyHiddenText';
import { getFocusables, tryCatch, withTestIds } from '../../utils';
import Button from '../Button';
import Icon, { registerIcon } from '../Icon';
import * as warnSolidIcon from '../Icon/icons/warn-solid.icon';
import * as flagWaveSolidIcon from '../Icon/icons/flag-wave-solid.icon';
import * as checkIcon from '../Icon/icons/check.icon';
import AdditionalInfo, { StyledAdditionalInfo } from '../AdditionalInfo';
import { getFormFieldTestIds } from './FormField.test-ids';
registerIcon(warnSolidIcon, flagWaveSolidIcon, checkIcon);
const StyledStatusIcon = styled(Icon)(({ theme, status }) => {
    return css `
    height: 1em;
    width: 1em;
    color: ${theme.components['form-field'][status]['status-color']};
    vertical-align: baseline;
    margin-inline-end: 0.5ch;
  `;
});
StyledStatusIcon.defaultProps = defaultThemeProp;
export const StyledFormFieldInfo = styled.div(({ status, theme: { base: { 'font-size': fontSize, 'font-scale': fontScale, spacing }, components: { 'form-field': formField } } }) => {
    const { xxs: infoFontSize } = calculateFontSize(fontSize, fontScale);
    return css `
      max-width: max-content;
      margin-top: calc(0.25 * ${spacing});
      font-size: ${infoFontSize};
      word-break: break-word;
      ${status &&
        formField[status] &&
        css `
        color: ${formField[status]['status-color']};
      `}
    `;
});
StyledFormFieldInfo.defaultProps = defaultThemeProp;
export const StyledLabelRow = styled.div ``;
export const StyledFormField = styled.div(props => {
    const { labelAsLegend, isRadioCheck, showAdditionalInfo, disabled, required, theme: { base: { palette: { urgent }, 'disabled-opacity': disabledOpacity, spacing, 'hit-area': { 'compact-min': hitAreaCompact } } } } = props;
    return css `
    ${disabled &&
        css `
      opacity: ${disabledOpacity};
      -webkit-user-select: none;
      user-select: none;
    `}
    position: relative;
    border: 0;

    > ${StyledLabel}, > ${StyledLabelRow} {
      &:not(:empty) {
        margin-bottom: calc(0.25 * ${spacing});
        min-height: ${hitAreaCompact};
      }
    }

    > ${StyledLabel}, > ${StyledLabelRow} > ${StyledLabel} {
      ${required &&
        css `
        &::after {
          content: ${'"\\00a0*" / " "'};
          color: ${urgent};
        }
      `}

      ${disabled &&
        css `
        cursor: not-allowed;
      `}
    }

    ${labelAsLegend &&
        css `
      > legend {
        display: inline-flex;
        align-items: flex-end;
      }
    `}

    ${labelAsLegend &&
        showAdditionalInfo &&
        css `
      display: block;

      > legend {
        float: inline-start;
      }

      > ${StyledAdditionalInfo} {
        ${!isRadioCheck &&
            css `
          float: inline-end;
        `}
        + * {
          clear: both;
        }
      }
    `}
  `;
});
StyledFormField.defaultProps = defaultThemeProp;
const StyledSuggestionButton = styled(Button)(({ theme: { base: { 'font-size': fontSize, 'font-scale': fontScale, 'border-radius': baseRadius, spacing }, components: { 'form-control': { 'border-radius': radius, 'border-width': borderWidth }, 'form-field': formField } } }) => {
    const { xxs: buttonFontSize } = calculateFontSize(fontSize, fontScale);
    const backgroundColor = formField.pending['status-color'];
    const hoverColors = getHoverColors(backgroundColor);
    const color = tryCatch(() => readableColor(backgroundColor));
    const borderColor = color ? rgba(color, 0.4) : color;
    return css `
    background-color: ${backgroundColor};
    color: ${color};
    font-size: ${buttonFontSize};
    min-width: calc(3 * ${spacing});
    min-height: calc(3 * ${spacing});
    padding: 0 ${spacing};
    border-radius: 0;
    border: none;

    &:first-child {
      border-inline-end: ${borderWidth} solid ${borderColor};
      border-end-start-radius: calc(${baseRadius} * ${radius});
      margin-inline-start: calc(2 * ${spacing});
    }

    &:last-child {
      border-end-end-radius: calc(${baseRadius} * ${radius});
      margin-inline-start: 0;
    }

    &:hover {
      color: ${hoverColors.foreground};
      background-color: ${hoverColors.background};
    }

    @media (pointer: coarse) {
      min-height: 2rem;
    }
  `;
});
StyledSuggestionButton.defaultProps = defaultThemeProp;
const statusIconMap = { error: 'warn-solid', warning: 'flag-wave-solid', success: 'check' };
const FormField = forwardRef(function FormField(props, ref) {
    const uid = useUID();
    const { testId, children: controlElement, id = uid, as = 'div', label, labelAs = 'label', labelFor = id, labelId, labelHidden = false, labelAfter = false, info, status, isRadioCheck, charLimitDisplay, required = false, disabled = false, readOnly = false, inline = false, actions, container, additionalInfo, 'aria-describedby': ariaDescribedBy, onResolveSuggestion, ...restProps } = props;
    const testIds = useTestIds(testId, getFormFieldTestIds);
    const t = useI18n();
    const { announceAssertive } = useLiveLog();
    const labelAsLegend = labelAs === 'legend';
    const hasSuggestion = status === 'pending' && !!onResolveSuggestion;
    const consolidatedRef = useConsolidatedRef(ref);
    const labelRef = useRef(null);
    const [labelText, setLabelText] = useState(null);
    const showAdditionalInfo = !!additionalInfo && !disabled && !labelHidden;
    const labelContent = (_jsxs(_Fragment, { children: [_jsx(Label, { "data-testid": testIds.label, id: labelId, as: labelAs, htmlFor: labelAs === 'label' ? labelFor : undefined, labelHidden: labelHidden, onClick: (e) => {
                    if (readOnly)
                        e.preventDefault();
                }, inline: inline, ref: labelRef, children: label }), showAdditionalInfo && labelText && (_jsx(AdditionalInfo, { "data-testid": testIds.additionalInfo, heading: additionalInfo.heading, contextualLabel: labelText, children: additionalInfo.content }))] }));
    const labelRow = !isRadioCheck && !labelAsLegend && !labelHidden ? (_jsx(Flex, { as: StyledLabelRow, container: { justify: 'between', alignItems: 'end' }, item: { alignSelf: 'stretch' }, children: labelContent })) : (labelContent);
    useEffect(() => {
        setLabelText(labelRef.current?.textContent ?? null);
    }, [label]);
    useEffect(() => {
        if (status === 'error' || status === 'warning') {
            let message = `${t(status)} ${info}`;
            if (labelRef.current?.textContent)
                message = `${labelRef.current?.textContent} ${message}`;
            announceAssertive({ message, type: status });
        }
    }, [status, info]);
    // fieldset or single form control element
    let content;
    if (labelAsLegend || Children.count(controlElement) > 1) {
        content = controlElement;
    }
    else {
        const controlElementAriaDescribedBy = Children.only(controlElement).props['aria-describedby'];
        content = cloneElement(controlElement, {
            'aria-describedby': [controlElementAriaDescribedBy, info && !readOnly ? `${id}-info` : undefined]
                .join(' ')
                .trim() || undefined
        });
    }
    if (actions) {
        content = (_jsxs(Flex, { container: { alignItems: 'center', gap: 0.5 }, children: [content, _jsx(Actions, { items: actions, menuAt: 3 })] }));
    }
    let infoContent = (_jsxs(Flex, { id: `${id}-info`, "data-testid": testIds.info, status: status, as: StyledFormFieldInfo, container: { alignItems: 'center' }, children: [status && status !== 'pending' && (_jsxs(_Fragment, { children: [_jsx(StyledStatusIcon, { status: status, name: statusIconMap[status] }), _jsx(VisuallyHiddenText, { children: `${t(status)} ` })] })), info] }));
    if (charLimitDisplay) {
        infoContent = (_jsxs(Flex, { container: { justify: infoContent ? 'between' : 'end', gap: 1 }, children: [infoContent, _jsx(Flex, { item: { shrink: 0 }, children: charLimitDisplay })] }));
    }
    if (hasSuggestion) {
        const focusables = getFocusables(consolidatedRef);
        infoContent = (_jsxs(Flex, { container: { alignItems: 'start', justify: 'between' }, children: [_jsxs(StyledFormFieldInfo, { "data-testid": testIds.info, status: status, id: `${id}-info`, children: [t('suggestion_info'), _jsx(VisuallyHiddenText, { "aria-live": 'polite', children: t('suggestion_assist') })] }), _jsxs(Flex, { container: { wrap: 'nowrap' }, children: [_jsx(StyledSuggestionButton, { "data-testid": testIds.suggestionReject, onClick: () => {
                                onResolveSuggestion(false);
                                focusables[0]?.focus();
                            }, "aria-label": t('reject_suggestion_button_a11y'), children: t('no') }), _jsx(StyledSuggestionButton, { "data-testid": testIds.suggestionAccept, onClick: () => {
                                onResolveSuggestion(true);
                                focusables[0]?.focus();
                            }, "aria-label": t('accept_suggestion_button_a11y'), children: t('yes') })] })] }));
    }
    const onKeyDown = (e) => {
        if (e.key === 'Enter') {
            const target = e.target;
            if (!target.closest('button')) {
                e.preventDefault();
                onResolveSuggestion?.(true);
            }
        }
    };
    const descriptionIds = [];
    if (ariaDescribedBy)
        descriptionIds.push(ariaDescribedBy);
    if (labelAsLegend && info)
        descriptionIds.push(`${id}-info`);
    return (_jsxs(Flex, { "data-testid": testIds.root, ...restProps, container: {
            direction: inline ? 'row' : 'column',
            alignItems: inline ? 'center' : undefined,
            ...container
        }, as: StyledFormField, labelAsLegend: labelAsLegend, isRadioCheck: isRadioCheck, showAdditionalInfo: showAdditionalInfo, id: `${id}-field`, forwardedAs: as, required: required, disabled: disabled, readOnly: readOnly, onKeyDown: hasSuggestion ? onKeyDown : undefined, "aria-describedby": descriptionIds.length ? descriptionIds.join(' ') : undefined, ref: consolidatedRef, children: [(labelAsLegend || !labelAfter) && labelRow, content, !labelAsLegend && labelAfter && labelRow, !readOnly && infoContent] }));
});
export default withTestIds(FormField, getFormFieldTestIds);
//# sourceMappingURL=FormField.js.map