import { useEffect, useState, ReactNode, FC, useRef } from 'react';
import { observer } from 'mobx-react';

import {
    FilePicker,
    ButtonGroup,
    Tooltip,
    Button,
    Card,
    Banner,
    Grid,
} from '@servicetitan/design-system';
import { Label } from '@servicetitan/form';

import { getImageSize, formatBytes } from '../../../utils/helpers';

export const LOGO_MIN_SIZE = 180;
export const DEFAULT_MIN_DIMENSIONS = { width: LOGO_MIN_SIZE, height: LOGO_MIN_SIZE };
export const DEFAULT_LOGO_TIPS = (
    <ul>
        <li>PNGs with a transparent background work best, but aren't required.</li>
        <li>
            Don't know where your logo is? Your social media profile would be a good place to look.
        </li>
        <li>Use a logo that is at least 180x180px in size.</li>
        <li>
            Avoid using a screenshot of your logo, right click and “save as” if you're pulling it
            from somewhere else.
        </li>
    </ul>
);

import * as Styles from './logo-picker.module.less';

export interface LogoPickerProps {
    error?: string;
    image?: File;
    imageUrl?: string;
    loaded?: boolean;
    maxSize?: number;
    minDimensions?: { width: number; height: number };
    tips?: ReactNode;
    deletable?: boolean;
    isGrid?: boolean;

    deleteImage(): void;
    downloadImage?(): void;
    onBadImage?(opts: { category: string; error: string; data: { imageUrl: string } }): void;
    onFileChange(files: FileList | null): void;
    setError?(error: string): void;
}

export const LogoPicker: FC<LogoPickerProps> = observer(
    ({
        deleteImage,
        downloadImage,
        error,
        image,
        imageUrl,
        loaded = true,
        maxSize,
        minDimensions = DEFAULT_MIN_DIMENSIONS,
        onBadImage,
        onFileChange,
        setError,
        deletable = true,
        tips = DEFAULT_LOGO_TIPS,
        isGrid = true,
    }) => {
        const [recommendLargerImage, setRecommendLargerImage] = useState(false);
        const [localError, setLocalError] = useState('');
        const [isLoading, setIsLoading] = useState(false);
        const [sizeError, setSizeError] = useState('');

        const formattedMaxSize = useRef(formatBytes(maxSize, 2, false));

        useEffect(() => {
            const handleImageUrlChange = async () => {
                if (!imageUrl || !minDimensions) {
                    return;
                }

                setIsLoading(true);
                try {
                    const size = await getImageSize(imageUrl);
                    setRecommendLargerImage(
                        size.height < minDimensions.height || size.width < minDimensions.width,
                    );
                    setLocalError('');

                    if (setError) {
                        setError('');
                    }
                } catch {
                    onBadImage?.({
                        category: 'LogoPicker',
                        error: 'Got a bad image',
                        data: { imageUrl },
                    });
                    deleteImage();

                    setLocalError('File is not a valid image');
                    setRecommendLargerImage(false);

                    if (setError) {
                        setError('File is not a valid image');
                    }
                } finally {
                    setIsLoading(false);
                }
            };
            handleImageUrlChange();
        }, [imageUrl, minDimensions, setError, deleteImage, onBadImage]);

        useEffect(() => {
            if (!image?.size || !maxSize) {
                return;
            }

            setIsLoading(true);

            if (image && image.size > maxSize) {
                deleteImage();

                setSizeError(`File size should be less than ${formattedMaxSize.current}.`);

                if (setError) {
                    setError(`File size should be less than ${formattedMaxSize.current}.`);
                }
            } else {
                setSizeError('');

                if (setError) {
                    setError('');
                }
            }

            setIsLoading(false);
        }, [image, maxSize, setError, deleteImage]);

        if (!loaded || isLoading) {
            return null;
        }

        return (
            <div className="field">
                <Label label="Logo" hasError={!!error || !!localError || !!sizeError} />
                {(error || localError) && (
                    <Banner
                        className="m-b-2 qa-settings-logo-error"
                        title={error ?? localError}
                        status="critical"
                        icon
                    />
                )}
                {sizeError && (
                    <Banner
                        className="m-b-2 qa-settings-logo-error"
                        title={sizeError}
                        status="critical"
                        icon
                    />
                )}
                {imageUrl === undefined ? (
                    <FilePicker
                        typesNote="Allowed file types: jpeg, png, jpg"
                        className="qa-settings-logo-file-picker"
                        accept="image/png, image/jpeg"
                        onSelected={onFileChange}
                    />
                ) : isGrid ? (
                    <Grid>
                        <Grid.Column width={4}>
                            <LogoCard
                                imageUrl={imageUrl}
                                onFileChange={onFileChange}
                                image={image}
                                downloadImage={downloadImage}
                                deletable={deletable}
                                deleteImage={deleteImage}
                            />
                        </Grid.Column>
                    </Grid>
                ) : (
                    <LogoCard
                        imageUrl={imageUrl}
                        onFileChange={onFileChange}
                        image={image}
                        downloadImage={downloadImage}
                        deletable={deletable}
                        deleteImage={deleteImage}
                    />
                )}
                {recommendLargerImage && minDimensions && (imageUrl || image) && (
                    <Banner
                        title={`We strongly recommend using a logo that is at least ${minDimensions.width}x${minDimensions.height}px in size. Using a lower-resolution image may result in logo pixelation in your templates.`}
                        className="m-t-2"
                        status="warning"
                        icon
                    />
                )}
                {(imageUrl === undefined || recommendLargerImage || localError || sizeError) && (
                    <Banner icon title="Tips on Uploading Your Logo:" className="m-t-2">
                        {tips}
                    </Banner>
                )}
            </div>
        );
    },
);

interface LogoCardProps {
    imageUrl: string;
    image?: File;
    deletable?: boolean;
    onFileChange(files: FileList | null): void;
    downloadImage?(): void;
    deleteImage(): void;
}

const LogoCard: FC<LogoCardProps> = ({
    imageUrl,
    onFileChange,
    image,
    downloadImage,
    deletable = true,
    deleteImage,
}) => {
    const fileRef = useRef<HTMLInputElement>(null);
    const handleClick = () => fileRef.current?.click();

    return (
        <Card raised padding="none" className={Styles.logoCard}>
            <Card.Section>
                <img className="qa-settings-logo-image" src={imageUrl} alt="logo" />
                <div className={Styles.logoAction}>
                    <ButtonGroup>
                        <Tooltip el="div" text="Replace">
                            <Button
                                outline
                                iconName="sync"
                                onClick={handleClick}
                                className="qa-settings-logo-replace shadow-1-i bg-white-i"
                            />
                            <input
                                hidden
                                type="file"
                                accept="image/png, image/jpeg"
                                ref={fileRef}
                                onChange={({ currentTarget: { files } }) => onFileChange(files)}
                            />
                        </Tooltip>
                        <Tooltip el="div" text="Download">
                            {downloadImage || image !== undefined ? (
                                <Button
                                    className="qa-settings-logo-download shadow-1-i bg-white-i"
                                    disabled={image !== undefined}
                                    onClick={downloadImage}
                                    iconName="file_download"
                                    outline
                                />
                            ) : (
                                <a
                                    download={`logo.${imageUrl.split('.').pop()}`}
                                    rel="noreferrer"
                                    target="_blank"
                                    href={imageUrl}
                                >
                                    <Button
                                        className="qa-settings-logo-download shadow-1-i bg-white-i"
                                        iconName="file_download"
                                        outline
                                    />
                                </a>
                            )}
                        </Tooltip>
                        {deletable && (
                            <Tooltip el="div" text="Delete">
                                <Button
                                    className="qa-settings-logo-delete shadow-1-i bg-white-i"
                                    onClick={deleteImage}
                                    iconName="delete"
                                    outline
                                />
                            </Tooltip>
                        )}
                    </ButtonGroup>
                </div>
            </Card.Section>
        </Card>
    );
};
