import {
    useCallback,
    useEffect,
    useMemo,
    useState,
} from 'react';

import _ from 'lodash';
import { Loader2 } from 'lucide-react';
import { swap } from 'react-grid-dnd';
import {
    LuMoveLeft,
    LuMoveRight,
    LuPlus,
    LuTrash,
} from 'react-icons/lu';

import { rpc } from '@/api/request';
import { StructureType } from '@/api/types';
import { toast } from '@/componentsRoot/ToastRoot';
import { Lang } from '@/lang/Lang';

import DataDescription from '../components/DataDescription';
import DataLabel from '../components/DataLabel';
import { ItemDataProps } from '../types';
import useAppConfigStore, { useAppConfig } from '@/stores/appConfig';

type ArrayImagesItemProps = {
    structure?: StructureType,
    value: any,
    onDelete?: () => void,
    onMoveRight?: () => void,
    onMoveLeft?: () => void,

}


const ArrayImagesItem = ({ structure, value, onDelete, onMoveRight, onMoveLeft }: ArrayImagesItemProps) => {



    if (!structure) {
        return <></>;
    }

    const url = useMemo(() => {
        if (structure.type == "fileImage" || structure.type == "fileImageID") {
            return value?.url_small ?? value?.url_medium ?? value?.url;
        }
        if (structure.type == "fileImageLink") {
            return value;
        }
        return null;
    }, [value]);


    const FabBtn = ({ children, className, onClick }: { children: React.ReactNode, className?: string, onClick?: () => void }) => {

        return <div className={` absolute cursor-pointer opacity-20 hover:opacity-100 rounded-xs p-1 text-white ${className}`} onClick={onClick}>
            {children}
        </div>
    }

    return <div className='w-full h-20 border border-gray-200 rounded-md bg-gray-200 overflow-hidden relative'>
        <div

            className='w-full h-20'
            style={{
                backgroundImage: `url(${url})`,
                backgroundSize: 'cover',
                backgroundPosition: 'center',
                backgroundRepeat: 'no-repeat',
            }}></div>

        {!!onDelete && <FabBtn className='top-0 right-0 bg-red-600' onClick={onDelete}>
            <LuTrash className='size-3' />
        </FabBtn>}



        {!!onMoveRight && <FabBtn className='bottom-0 right-0 bg-blue-600' onClick={onMoveRight}>
            <LuMoveRight className='size-3' />
        </FabBtn>}
        {!!onMoveLeft && <FabBtn className='bottom-0 left-0 bg-blue-600' onClick={onMoveLeft}>
            <LuMoveLeft className='size-3' />
        </FabBtn>}

    </div>
}



const ArrayImagesGridItem = ({ onClick, loading, plus = false, disabled = false }: { onClick?: () => void, loading?: boolean, plus?: boolean, disabled?: boolean }) => {
    return <div

        style={{
            opacity: disabled ? 0.5 : 1,
            cursor: disabled ? 'not-allowed' : 'pointer',
        }}
        onClick={() => {
            onClick?.();
        }}
        className='w-full h-20 border border-gray-200 rounded-md bg-gray-200 flex items-center justify-center cursor-pointer hover:bg-gray-100 transition-all duration-300'>
        {plus && <LuPlus className='size-5' />}
        {loading && <Loader2 className='size-5 animate-spin' />}
    </div>
}


const selectImageFile = (accept?: string): Promise<File[] | null> => {
    return new Promise((resolve) => {
        const input = document.createElement('input');
        input.type = 'file';
        input.accept = !!accept ? accept : 'image/*';
        input.style.display = 'none';
        input.multiple = true;

        input.addEventListener('change', () => {
            const files = [];
            for (const file of input.files ?? []) {
                files.push(file);
            }
            input.remove();
            resolve(files);
        });
        input.onerror = () => {
            resolve(null);
        };
        input.onabort = () => {
            resolve(null);
        };

        document.body.appendChild(input);
        input.click();
    });
}


const ArrayImages = (props: ItemDataProps) => {

    const { isMobile } = useAppConfigStore();

    const onlyShow = props.onlyShow || !props.structure.editable;

    const [localValue, setLocalValue] = useState(props.getValue() ?? []);
    const [forceUpdate, setForceUpdate] = useState(false);



    useEffect(() => {
        props.setValue(localValue);
    }, [localValue]);

    useEffect(() => {
        if (forceUpdate) {
            setForceUpdate(false);
        }
    }, [forceUpdate]);


    const [pendingUploads, setPendingUploads] = useState<File[]>([]);

    const itemType = props.structure.itemType?.type ?? 'fileImage';
    const isUploading = pendingUploads.length > 0;

    const uploadFilesSequentially = useCallback(async (files: File[]) => {
        setPendingUploads(files);
        for (const file of files) {
            const formData = new FormData();
            formData.append('file', file);
            try {
                const json = await rpc.imageUpload(formData);
                if (json) {
                    const item = itemType === 'fileImageLink' ? (json.url ?? '') : json;
                    setLocalValue((prev: unknown[]) => [...prev, item]);
                }
            } catch {
                toast.error(Lang.key('error_uploading_image'));
            } finally {
                setPendingUploads((prev) => prev.slice(1));
            }
        }
    }, [itemType]);

    if (onlyShow) {
        return <div>
            <DataLabel {...props} />
            <div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 2xl:grid-cols-8 gap-2">
                {_.map(localValue, (item, index) => (
                    <ArrayImagesItem
                        key={item?.uuid ?? item?._id ?? index}
                        structure={props.structure.itemType}
                        value={item}
                    />
                ))}
            </div>
            <DataDescription {...props} />
        </div>
    }

    return <div>


        <DataLabel {...props} />

        <div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 2xl:grid-cols-8 gap-2">

            {_.map(localValue, (item, index) => (
                <ArrayImagesItem
                    onMoveRight={() => {
                        setLocalValue((prev: unknown[]) => swap(prev, index, index + 1));
                    }}
                    onMoveLeft={() => {
                        setLocalValue((prev: unknown[]) => swap(prev, index, index - 1));
                    }}
                    onDelete={() => {
                        setLocalValue((prev: unknown[]) => prev.filter((_, i) => i !== index));
                    }}
                    key={item?.uuid ?? item?._id ?? index}
                    structure={props.structure.itemType}
                    value={item}
                />
            ))}
            {_.map(pendingUploads, (file, index) => (
                <ArrayImagesGridItem
                    key={`${file.name}-${file.lastModified}-${file.size}-${index}`}
                    loading
                />
            ))}
            <ArrayImagesGridItem
                plus
                disabled={isUploading}
                onClick={() => {
                    if (isUploading) return;
                    selectImageFile().then((files) => {
                        if (files?.length) {
                            uploadFilesSequentially(files);
                        }
                    });
                }}
            />



        </div>
        <DataDescription {...props} />



    </div>
}

export default ArrayImages;