import React from 'react';
import { GlyphIcon } from '@theorchard/suite-icons';
import cx from 'classnames';
import { Label, GlyphButton, Form, Tooltip, LoadingSpinner } from '../index';
import type { MetadataProps } from '../metadata';

const CLASS_NAME = 'EditableMetadata';

export interface EditableMetadataProps extends Omit<MetadataProps, 'children'> {
    value: string;
    onConfirm: (value: string) => void;
    validationFn?: (value: string) => boolean;
    validationError?: string;
    processing?: {
        type: 'loading' | 'success';
        message?: string;
    };
    style?: React.CSSProperties;
}

/**
 * EditableMetadata is a component that allows users to edit a string Metadata value
 *
 * @tags form-elements
 * @status live
 * @type molecule
 */
export const EditableMetadata: React.FC<EditableMetadataProps> = ({
    className,
    style,
    value,
    testId = CLASS_NAME,
    layout,
    label,
    onConfirm,
    validationFn,
    validationError,
    processing,
}) => {
    const inputRef = React.useRef<HTMLInputElement>(null);
    const [isEditing, setIsEditing] = React.useState(false);
    const [hasError, setHasError] = React.useState(false);
    const [isFadingOut, setIsFadingOut] = React.useState(false);
    const [fadeProcessing, setFadeProcessing] = React.useState<typeof processing>(processing);

    // Update input value when props change
    React.useEffect(() => {
        if (inputRef.current) {
            inputRef.current.value = value;
        }
    }, [value]);

    // Focus the input at the last character when entering edit mode
    React.useEffect(() => {
        if (isEditing && inputRef.current) {
            inputRef.current.focus();
            const length = inputRef.current.value.length;
            inputRef.current.setSelectionRange(length, length);
        }
    }, [isEditing]);

    // Handle the fading effect for the processing state changes, specially from "success" to none
    React.useEffect(() => {
        if (processing === undefined && fadeProcessing) {
            setIsFadingOut(true);

            const timer = setTimeout(() => {
                setIsFadingOut(false);
                setFadeProcessing(undefined);
            }, 300);

            return () => clearTimeout(timer);
        } else if (processing) {
            setIsFadingOut(false);
            setFadeProcessing(processing);
        }
    }, [processing, fadeProcessing]);

    const saveEdit = () => {
        if (inputRef.current) {
            onConfirm(inputRef.current.value);
            setIsEditing(false);
        }
    };

    return (
        <div data-testid={testId} className={cx(CLASS_NAME, className, layout)} style={style}>
            {typeof label === 'string' ? <Label text={label} /> : <Label {...label} />}

            <div className={`${CLASS_NAME}-container`}>
                <div className={`${CLASS_NAME}-value`}>
                    {isEditing ? (
                        <Tooltip
                            id="edit-tooltip-error"
                            className={`${CLASS_NAME}-tooltip-error`}
                            message={validationError || ''}
                            show={!!validationError && hasError}
                            placement="bottom"
                        >
                            <Form.Control
                                ref={inputRef}
                                id={`${CLASS_NAME}-edit-input`}
                                className={`${CLASS_NAME}-edit-input`}
                                defaultValue={value}
                                onChange={(e) => {
                                    if (validationFn && validationFn(e.target.value)) {
                                        setHasError(false);
                                    } else {
                                        setHasError(true);
                                    }
                                }}
                            />
                        </Tooltip>
                    ) : (
                        <>
                            <span
                                className={`${CLASS_NAME}-read-input`}
                                data-testid="read-input"
                                onClick={() => setIsEditing(!isEditing)}
                            >
                                {value}
                            </span>

                            {!fadeProcessing ? (
                                <GlyphButton
                                    className={`${CLASS_NAME}-edit-button`}
                                    testId={`${CLASS_NAME}-edit-button`}
                                    name="edit"
                                    size="sm"
                                    variant="control"
                                    onClick={() => setIsEditing(!isEditing)}
                                    aria-label="TODO:Int: Edit"
                                />
                            ) : (
                                <div
                                    className={cx(`${CLASS_NAME}-processing`, {
                                        'fade-out': isFadingOut,
                                    })}
                                    title={fadeProcessing?.message}
                                >
                                    {fadeProcessing?.type === 'loading' && (
                                        <LoadingSpinner
                                            className={`${CLASS_NAME}-loading`}
                                            show
                                            size={16}
                                        />
                                    )}
                                    {fadeProcessing?.type === 'success' && (
                                        <GlyphIcon
                                            className={`${CLASS_NAME}-success`}
                                            testId={`${CLASS_NAME}-success`}
                                            name="check"
                                            size={16}
                                        />
                                    )}
                                </div>
                            )}
                        </>
                    )}
                </div>

                <div className={`${CLASS_NAME}-actions`}>
                    {isEditing && (
                        <>
                            <GlyphButton
                                testId={`${CLASS_NAME}-save-button`}
                                name="check"
                                variant="secondary"
                                size="sm"
                                disabled={hasError}
                                aria-label="TODO:Int: Save Edit"
                                onClick={() => saveEdit()}
                            />
                            <GlyphButton
                                testId={`${CLASS_NAME}-cancel-button`}
                                name="close"
                                variant="control"
                                size="sm"
                                aria-label="TODO:Int: Cancel Edit"
                                onClick={() => {
                                    if (inputRef.current) {
                                        inputRef.current.value = value;
                                    }
                                    setIsEditing(!isEditing);
                                }}
                            />
                        </>
                    )}
                </div>
            </div>
        </div>
    );
};

export default EditableMetadata;
