import type { FC } from 'react';
import React, { useState } from 'react';
import { GlyphIcon } from '@theorchard/suite-icons';
import cx from 'classnames';
import { Link } from 'react-router-dom';
import { Button } from '../bootstrap';
import { Card } from '../card';
import { Expandable } from '../expandable';
import { GlyphButton } from '../glyphButton';
import { AlertContainer } from './alertContainer';
import type { ButtonProps } from '../bootstrap';
import type { GlyphName24PX } from '@theorchard/suite-icons';

export const CLASS_NAME = 'Alert';

export interface AlertProps {
    children?: React.ReactNode;
    className?: string;
    testId?: string;
    variant: 'error' | 'warn' | 'success' | 'information' | 'flag';
    color?: 'error' | 'warn' | 'success' | 'information';
    text: string | React.ReactNode;
    title?: string | undefined;
    dismissible?: boolean;
    onDismiss?: (dismissAlert: () => void) => void;
    button?: Omit<ButtonProps, 'onClick'> & {
        text: string;
        onClick: (dismissAlert: () => void) => void;
    };
    link?: { text: string; to: string };
    /**
     * When true and title is provided, allows collapsing the alert content.
     * Only works when title is present.
     */
    expandable?: boolean;
    /**
     * Initial expanded state when expandable is true.
     * @default true
     */
    defaultExpanded?: boolean;
}

interface Alert extends FC<AlertProps> {
    /**
     * A auto-fitting container for alerts that is collapsible
     */
    Container: typeof AlertContainer;
}

/**
 * Alerts are contextual messages that highlight information in a persistent manner. They're inline elements with core and optional properties that affect their function.
 *
 * @type molecule
 * @status live
 * @tags feedback
 *
 * @nested AlertContainer
 */
const Alert: Alert = ({
    className,
    testId = CLASS_NAME,
    variant,
    color = variant === 'flag' ? 'error' : variant,
    text,
    title,
    link,
    button,
    dismissible,
    onDismiss,
    expandable,
    defaultExpanded = true,
}) => {
    const [open, setOpen] = useState(true);

    const isExpandable = expandable && !!title;

    if (!open) return null;

    const hide = () => {
        if (onDismiss) onDismiss(() => setOpen(false));
        else setOpen(false);
    };

    const getAlertGlyph = (variant: AlertProps['variant']): GlyphName24PX => {
        switch (variant) {
            case 'information':
                return 'info';
            case 'success':
                return 'success';
            case 'flag':
                return 'flag';
            default:
                return 'warning';
        }
    };

    const renderCardContentTop = () => (
        <div className={`${CLASS_NAME}-content content-top`}>
            <div className={`${CLASS_NAME}-icons`}>
                <GlyphIcon size={24} name={getAlertGlyph(variant)} />
            </div>

            <div className={`${CLASS_NAME}-elements`}>
                {title && <h5 className={`${CLASS_NAME}-title`}>{title}</h5>}
                {/* We need this rendering conditionally so avoid DOM breaking change or apply css hacks */}
                {!isExpandable && <div className={`${CLASS_NAME}-text`}>{text}</div>}
            </div>

            {renderControls()}
        </div>
    );

    const renderCardContentBottom = () => {
        const CollapsibleWrapper = isExpandable ? Expandable.Body : React.Fragment;

        return (
            <CollapsibleWrapper {...(isExpandable ? { className: 'content-bottom' } : {})}>
                {isExpandable && <div className={`${CLASS_NAME}-text`}>{text}</div>}

                {(button || link) && (
                    <div className={`${CLASS_NAME}-actions`}>
                        {button && (
                            <Button
                                className={`${CLASS_NAME}-button`}
                                onClick={() => button.onClick(hide)}
                                variant="tertiary"
                                {...(({ text, onClick, ...rest }) => rest)(button)}
                            >
                                {button.text}
                            </Button>
                        )}
                        {link && (
                            <Link className={`${CLASS_NAME}-link`} to={link.to}>
                                {link.text}
                            </Link>
                        )}
                    </div>
                )}
            </CollapsibleWrapper>
        );
    };

    const renderControls = () => {
        if (!isExpandable && !dismissible) return null;

        return (
            <div className={`${CLASS_NAME}-controls`}>
                {isExpandable && (
                    <Expandable.Trigger
                        className={`${CLASS_NAME}-toggle`}
                        testId={`${testId}-toggle`}
                    />
                )}

                {dismissible && (
                    <GlyphButton
                        className={`${CLASS_NAME}-close`}
                        variant="control"
                        onClick={hide}
                        name="close"
                    />
                )}
            </div>
        );
    };

    return (
        <Expandable
            as={Card}
            isExpandable={isExpandable}
            defaultExpanded={defaultExpanded}
            className={cx(CLASS_NAME, className, `${CLASS_NAME}-${color}`, {
                [`${CLASS_NAME}-expandable`]: isExpandable,
                [`${CLASS_NAME}-dismissible`]: dismissible,
            })}
            testId={testId}
        >
            <Card.Body className={`${CLASS_NAME}-body`}>
                {renderCardContentTop()}
                {renderCardContentBottom()}
            </Card.Body>
        </Expandable>
    );
};

Alert.Container = AlertContainer;

export { Alert };
