import type { FC } from 'react';
import React from 'react';
import { formatMessage } from '@theorchard/suite-i18n';
import { Illustration } from '@theorchard/suite-icons';
import cx from 'classnames';
import { Button } from '../bootstrap';
import type { ButtonProps } from '../bootstrap';
import type { IllustrationName, IllustrationProps } from '@theorchard/suite-icons';

const CLASS_NAME = 'ErrorMessage';

export interface ErrorMessageProps {
    className?: string;
    style?: React.CSSProperties;
    testId?: string;
    title?: string;
    description?: string;
    // @deprecated Use `title` prop.
    message?: string;
    /**
     * Only used by internal tooling to emit error messages.
     */
    error?: Error;
    /**
     * Only used by suite-frontend for backend errors.
     */
    code?: string;
    // @deprecated Use `illustration` or `customIllustration`
    icon?: FC | false;
    /**
     * Can be used for custom illustrations not in our library.
     */
    customIllustration?: FC;
    /**
     * Illustration shown at the top of the error message.
     */
    illustration?: IllustrationName;
    // @deprecated Use `variant`
    size?: 'sm' | 'lg';
    /**
     * Determines size and orientation of the error message.
     * Note that sm/lg are deprecated.
     */
    variant?: 'full-page' | 'large' | 'medium' | 'small';
    // @deprecated Use `button`
    children?: React.ReactNode;
    /**
     * Width of the component.
     * @default 400
     */
    width?: number;

    /**
     * Button rendered below description.
     */
    button?: ButtonProps & { text: React.ReactNode };
}

const mapIllustrationSize: Record<string, IllustrationProps['size']> = {
    sm: 100,
    lg: 200,
    'full-page': 200,
    large: 100,
    medium: 100,
    small: 50,
};

/**
 * ErrorMessage is a notification that appears in the UI to inform users of a problem and how to fix it.
 *
 * @type molecule
 * @status live
 * @tags feedback
 */
export const ErrorMessage: FC<ErrorMessageProps> = ({
    className,
    style,
    testId = CLASS_NAME,
    message,
    error,
    code = 'generic',
    icon,
    illustration,
    size,
    variant,
    title,
    description,
    width,
    button,
    children,
}) => {
    const errorVariant = variant ?? size ?? 'lg';
    const errorTitle = title ?? formatMessage(`error_${code}_title`);
    const illustrationSize = mapIllustrationSize[errorVariant] ?? 200;
    const errorDescription =
        description ?? message ?? error?.message ?? formatMessage(`error_${code}_message`);

    const ErrorIllustration = () => {
        const IconComponent = icon;
        if (IconComponent) return <IconComponent />;
        if (illustration) return <Illustration name={illustration} size={illustrationSize} />;

        return <Illustration name="fatalError" size={illustrationSize} />;
    };

    const ErrorHeader = () => {
        let Header: keyof JSX.IntrinsicElements = 'h4';
        if (errorVariant === 'full-page') Header = 'h1';
        else if (errorVariant === 'lg') Header = 'h1';
        return <Header className={`${CLASS_NAME}-title`}>{errorTitle}</Header>;
    };

    return (
        <div
            className={cx(CLASS_NAME, className, `${CLASS_NAME}-${errorVariant}`)}
            data-testid={testId}
            style={{ width, ...style }}
        >
            <div className={`${CLASS_NAME}-illustration`}>
                <ErrorIllustration />
            </div>
            <div className={`${CLASS_NAME}-content`}>
                <div className={`${CLASS_NAME}-content-text`}>
                    <ErrorHeader />
                    <div className={`${CLASS_NAME}-description`}>{errorDescription}</div>
                </div>
                {children ||
                    (button && (
                        <p className={`${CLASS_NAME}-body`}>
                            <Button size={variant === 'small' ? undefined : 'lg'} {...button}>
                                {button.text}
                            </Button>
                            {children}
                        </p>
                    ))}
            </div>
        </div>
    );
};
