import React, { forwardRef, useEffect, useRef, useState } from "react";
import { canUseDOM, cx, getSizeValueFromProp } from "../../utils";
import { useForkRef, useResizeObserver } from "../../hooks";
import { IconArrowBarDown } from "../_Icon";
import { base as viewCSS } from "./variations/_view/base";
import { base as sizeCSS } from "./variations/_size/base";
import { base as disabledCSS } from "./variations/_disabled/base";
import { base, Content, Description, DescriptionHelper, DropzoneHandlerOverlay, HiddenInput, StyledIcon, Title, TitleHelper, ContentWrapper, IconWrapper } from "./Dropzone.styles";
import { classes, privateTokens } from "./Dropzone.tokens";
export const dropzoneRoot = (Root)=>/*#__PURE__*/ forwardRef(({ files, className, style, accept, multiple, title, description, icon, iconPlacement = 'left', size, view, disabled, stretch, width, height, onDragEnter, onDragLeave, onDragOver, onDrop, validator, onClick, onChange, onChoseFiles, ...rest }, outerRef)=>{
        const [isDropzoneActive, setIsDropzoneActive] = useState(false);
        const [innerTitle, setInnerTitle] = useState(title);
        const [innerDescription, setInnerDescription] = useState(description);
        const [innerFiles, setInnerFiles] = useState([]);
        const currentFiles = files !== undefined ? files : innerFiles;
        const inputRef = useRef(null);
        const forkInputRef = useForkRef(outerRef, inputRef);
        const contentRef = useRef(null);
        const iconWrapperRef = useRef(null);
        const iconRef = useRef(null);
        const contentWrapperRef = useRef(null);
        const titleRef = useRef(null);
        const titleHelperRef = useRef(null);
        const descriptionRef = useRef(null);
        const descriptionHelperRef = useRef(null);
        const innerWidth = width ? getSizeValueFromProp(width) : 'fit-content';
        const innerHeight = height ? getSizeValueFromProp(height) : 'fit-content';
        const isTitleString = typeof title === 'string';
        const isDescriptionString = typeof description === 'string';
        const processFiles = async (rawFiles, callback, afterAction)=>{
            if (!rawFiles?.length) {
                return;
            }
            const files = [
                ...rawFiles
            ];
            let res = {
                acceptedFiles: files
            };
            if (validator) {
                res = await validator?.(files);
            }
            if (callback) {
                await callback(res);
            }
            if (afterAction) {
                afterAction();
            }
        };
        const handleDragEnter = (event)=>{
            if (disabled) {
                return;
            }
            event.preventDefault();
            event.stopPropagation();
            if (onDragEnter) {
                onDragEnter(event);
            }
            setIsDropzoneActive(true);
        };
        const handleDragLeave = (event)=>{
            if (disabled) {
                return;
            }
            event.preventDefault();
            if (onDragLeave) {
                onDragLeave(event);
            }
            setIsDropzoneActive(false);
        };
        const handleDragOver = (event)=>{
            if (disabled) {
                return;
            }
            event.preventDefault();
            if (onDragOver) {
                onDragOver(event);
            }
            const { files: rawFiles } = event.dataTransfer;
            if (!isDropzoneActive && rawFiles && rawFiles.length > 0) {
                setIsDropzoneActive(true);
            }
        };
        const handleDrop = async (event)=>{
            if (disabled) {
                return;
            }
            event.preventDefault();
            event.persist();
            const { files: rawFiles } = event.dataTransfer;
            const afterAction = ()=>{
                event.dataTransfer.clearData();
                setIsDropzoneActive(false);
            };
            await processFiles(rawFiles, onDrop, afterAction);
        };
        const handleClick = (event)=>{
            if (!inputRef.current || disabled) {
                return;
            }
            inputRef.current.click();
            if (onClick) {
                onClick(event);
            }
        };
        const handleChange = async (event)=>{
            if (disabled) {
                return;
            }
            if (onChange) {
                onChange(event);
            }
            const { files: rawFiles } = event.target;
            await processFiles(rawFiles, async (res)=>{
                setInnerFiles(res.acceptedFiles);
                if (onChoseFiles) {
                    await onChoseFiles(res);
                }
            });
        };
        const truncateContent = ()=>{
            if (!canUseDOM || !descriptionRef?.current || !contentWrapperRef?.current || !titleRef?.current || !titleHelperRef?.current || !iconRef?.current || !iconWrapperRef?.current || !contentRef?.current || !descriptionHelperRef?.current || !width && !height) {
                return;
            }
            const contentHeight = contentRef.current.offsetHeight;
            const iconHeight = iconRef.current.offsetHeight;
            const iconWidth = iconPlacement === 'top' ? 0 : iconRef.current.offsetWidth;
            const titleHeight = titleRef.current.offsetHeight;
            const iconContentGap = iconPlacement === 'top' ? Number(window.getComputedStyle(iconWrapperRef.current).rowGap.replace('px', '')) : 0;
            const availableWidth = contentRef.current.offsetWidth - iconWidth - iconContentGap;
            const contentGap = Number(window.getComputedStyle(contentWrapperRef.current).rowGap.replace('px', ''));
            const titleFontWidth = Math.floor(titleHelperRef.current.offsetWidth);
            const titleFontHeight = Math.floor(titleHelperRef.current.offsetHeight);
            const descriptionFontWidth = Math.floor(descriptionHelperRef.current.offsetWidth);
            const descriptionFontHeight = Math.floor(descriptionHelperRef.current.offsetHeight);
            const titleAvailableHeight = contentHeight - iconHeight - iconContentGap - descriptionFontHeight - contentGap;
            const titleMaxChars = Math.floor(availableWidth / titleFontWidth * (titleAvailableHeight / titleFontHeight));
            let resTitleLength = 0;
            if (title && isTitleString) {
                const newTitle = title.length <= titleMaxChars ? title : `${title.slice(0, titleMaxChars - 3)}...`;
                resTitleLength = newTitle.length;
                setInnerTitle(newTitle);
            }
            const resultTitleHeight = Math.floor(titleFontHeight * titleFontWidth * resTitleLength / availableWidth);
            const descriptionAvailableHeight = titleAvailableHeight >= titleHeight + 2 * descriptionFontHeight ? contentHeight - resultTitleHeight - iconContentGap - contentGap : descriptionFontHeight;
            const descriptionMaxChars = Math.floor(availableWidth / descriptionFontWidth * (descriptionAvailableHeight / descriptionFontHeight));
            if (description && isDescriptionString) {
                const newDescription = description.length <= descriptionMaxChars ? description : `${description.slice(0, descriptionMaxChars - 3)}...`;
                setInnerDescription(newDescription);
            }
        };
        useResizeObserver(contentRef, truncateContent);
        useEffect(()=>{
            truncateContent();
        }, [
            title,
            description,
            iconPlacement
        ]);
        useEffect(()=>{
            if (inputRef.current) {
                inputRef.current.value = '';
            }
        }, [
            currentFiles
        ]);
        return /*#__PURE__*/ React.createElement(Root, {
            className: cx(className, isDropzoneActive && classes.active, stretch && classes.stretch, disabled && classes.disabled),
            view: view,
            size: size,
            disabled: disabled,
            tabIndex: 0,
            style: {
                ...style,
                [privateTokens.width]: innerWidth,
                [privateTokens.height]: innerHeight
            }
        }, /*#__PURE__*/ React.createElement(DropzoneHandlerOverlay, {
            onDragEnter: handleDragEnter,
            onDragLeave: handleDragLeave,
            onDragOver: handleDragOver,
            onDrop: handleDrop,
            onClick: handleClick
        }), /*#__PURE__*/ React.createElement(Content, {
            ref: contentRef
        }, /*#__PURE__*/ React.createElement(IconWrapper, {
            ref: iconWrapperRef,
            className: cx(iconPlacement === 'top' && classes.verticalContentPlacing)
        }, /*#__PURE__*/ React.createElement(StyledIcon, {
            ref: iconRef
        }, icon || /*#__PURE__*/ React.createElement(IconArrowBarDown, {
            color: "inherit",
            size: "s"
        })), /*#__PURE__*/ React.createElement(ContentWrapper, {
            ref: contentWrapperRef
        }, title && isTitleString ? /*#__PURE__*/ React.createElement(React.Fragment, null, /*#__PURE__*/ React.createElement(Title, {
            ref: titleRef
        }, innerTitle), /*#__PURE__*/ React.createElement(TitleHelper, {
            ref: titleHelperRef
        }, "C")) : title, description && isDescriptionString ? /*#__PURE__*/ React.createElement(React.Fragment, null, /*#__PURE__*/ React.createElement(Description, {
            ref: descriptionRef
        }, innerDescription), /*#__PURE__*/ React.createElement(DescriptionHelper, {
            ref: descriptionHelperRef
        }, "C")) : description))), /*#__PURE__*/ React.createElement(HiddenInput, {
            ref: forkInputRef,
            type: "file",
            accept: accept,
            multiple: multiple,
            tabIndex: -1,
            onChange: handleChange,
            ...rest
        }));
    });
export const dropzoneConfig = {
    name: 'Dropzone',
    tag: 'div',
    layout: dropzoneRoot,
    base,
    variations: {
        view: {
            css: viewCSS
        },
        size: {
            css: sizeCSS
        },
        disabled: {
            css: disabledCSS,
            attrs: true
        }
    },
    defaults: {
        view: 'default',
        size: 'm'
    }
};
