var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { Box, Flex, Image, Text } from "@theme-ui/components";
import { useEffect, useRef, useState } from "react";
import { DesktopOnly } from "../../components/responsive";
import { Icon } from "@notesnook/ui";
import { Icons } from "../../toolbar/icons";
import { ToolbarGroup } from "../../toolbar/components/toolbar-group";
import { useIsMobile, useToolbarStore } from "../../toolbar/stores/toolbar-store";
import { Resizer } from "../../components/resizer";
import { corsify, downloadImage, revokeBloburl, toBlobURL, toDataURL } from "../../utils/downloader";
import { motion } from "framer-motion";
import { useObserver } from "../../hooks/use-observer";
import DataURL from "@notesnook/core/dist/utils/dataurl";
export const AnimatedImage = motion(Image);
export function ImageComponent(props) {
    const { editor, node, selected } = props;
    const { src, alt, title, textDirection, hash, aspectRatio, mime, progress } = node.attrs;
    const [bloburl, setBloburl] = useState(toBlobURL("", "image", mime, hash));
    const controllerRef = useRef(new AbortController());
    const isMobile = useIsMobile();
    const { inView, ref: imageRef } = useObserver({
        threshold: 0.2,
        once: true
    });
    const dom = editor.view.dom.parentElement || editor.view.dom;
    const size = editor.view.dom.clientWidth === 0
        ? node.attrs
        : clampSize(node.attrs, dom.clientWidth, aspectRatio);
    const float = isMobile ? false : node.attrs.float;
    let align = node.attrs.align;
    if (!align)
        align = textDirection ? "right" : "left";
    const downloadOptions = useToolbarStore((store) => store.downloadOptions);
    const isReadonly = !editor.isEditable;
    const isSVG = !!mime && mime.includes("/svg");
    useEffect(() => {
        if (!inView)
            return;
        if (src || !hash || bloburl)
            return;
        (function () {
            return __awaiter(this, void 0, void 0, function* () {
                var _a, _b;
                const { hash } = node.attrs;
                if (hash) {
                    const data = yield ((_b = (_a = editor.storage).getAttachmentData) === null || _b === void 0 ? void 0 : _b.call(_a, {
                        type: "image",
                        hash
                    }).catch(() => null));
                    if (typeof data !== "string" || !data)
                        return; // TODO: show error
                    setBloburl(toBlobURL(data, "image", node.attrs.mime, hash));
                }
            });
        })();
    }, [inView]);
    useEffect(() => {
        const controller = controllerRef.current;
        return () => {
            controller.abort();
            if (hash)
                revokeBloburl(hash);
        };
    }, []);
    return (_jsx(_Fragment, { children: _jsx(Box, { sx: Object.assign(Object.assign({}, getAlignmentStyles(node.attrs)), { height: float ? size.height : "unset", position: "relative", mt: isSVG ? `24px` : 0, ":hover .drag-handle, :active .drag-handle": {
                    opacity: 1
                } }), children: _jsxs(Resizer, { style: { marginTop: 5 }, enabled: editor.isEditable && !float, selected: selected, width: size.width, height: size.height, onResize: (width, height) => {
                    editor.commands.setImageSize({ width, height });
                }, children: [_jsx(DesktopOnly, { children: selected && (_jsx(Flex, { sx: {
                                position: "absolute",
                                top: -40,
                                right: 0,
                                mb: 2,
                                alignItems: "end",
                                zIndex: 999
                            }, children: _jsx(ToolbarGroup, { editor: editor, tools: isReadonly
                                    ? [
                                        hash ? "previewAttachment" : "none",
                                        hash ? "downloadAttachment" : "none"
                                    ]
                                    : [
                                        hash ? "previewAttachment" : "none",
                                        hash ? "downloadAttachment" : "none",
                                        "imageAlignLeft",
                                        "imageAlignCenter",
                                        "imageAlignRight",
                                        "imageFloat",
                                        "imageProperties"
                                    ], sx: {
                                    boxShadow: "menu",
                                    borderRadius: "default",
                                    bg: "background"
                                } }) })) }), progress ? (_jsxs(Flex, { sx: {
                            position: "absolute",
                            bottom: 2,
                            right: 2,
                            bg: "background",
                            borderRadius: 100,
                            p: 1,
                            px: 2,
                            border: "1px solid var(--border)",
                            zIndex: 2
                        }, children: [_jsx(Icon, { path: Icons.loading, rotate: true, size: 14, sx: { mr: 1 } }), _jsxs(Text, { variant: "body", children: [progress, "%"] })] })) : null, !isReadonly && selected && (_jsx(Icon, { className: "drag-handle", "data-drag-handle": true, draggable: true, path: Icons.dragHandle, color: "black", sx: {
                            cursor: "grab",
                            position: "absolute",
                            top: 1,
                            left: 1,
                            zIndex: 999
                        } })), isSVG ? (_jsx(Box, { sx: {
                            width: "100%",
                            display: editor.isEditable ? "flex" : "none",
                            position: "absolute",
                            top: -24,
                            height: 24,
                            justifyContent: "end",
                            p: "small",
                            bg: editor.isEditable
                                ? "var(--background-secondary)"
                                : "transparent",
                            borderTopLeftRadius: "default",
                            borderTopRightRadius: "default",
                            borderColor: selected ? "border" : "var(--border-secondary)",
                            cursor: "pointer",
                            ":hover": {
                                borderColor: "border"
                            }
                        } })) : null, !src && !bloburl && hash && (_jsx(Flex, { sx: {
                            position: "absolute",
                            top: 0,
                            left: 0,
                            width: editor.isEditable && !float ? "100%" : size.width,
                            height: editor.isEditable && !float ? "100%" : size.height,
                            bg: "background-secondary",
                            border: selected
                                ? "2px solid var(--accent)"
                                : "2px solid transparent",
                            borderRadius: "default",
                            flexDirection: "column",
                            alignItems: "center",
                            justifyContent: "center",
                            // mt: 1,
                            py: 50
                        }, children: _jsx(Icon, { path: Icons.image, size: size.width ? size.width * 0.2 : 72, color: "gray" }) })), _jsx(AnimatedImage, Object.assign({ as: isSVG ? "object" : "img", initial: { opacity: 0 }, animate: { opacity: bloburl || src ? 1 : 0 }, transition: { duration: 0.2, ease: "easeIn" }, "data-drag-image": true, ref: imageRef, alt: alt, crossOrigin: "anonymous" }, (isSVG
                        ? {
                            data: bloburl || corsify(src, downloadOptions === null || downloadOptions === void 0 ? void 0 : downloadOptions.corsHost),
                            type: mime
                        }
                        : {
                            src: bloburl || corsify(src, downloadOptions === null || downloadOptions === void 0 ? void 0 : downloadOptions.corsHost)
                        }), { title: title, sx: {
                            objectFit: "contain",
                            width: editor.isEditable ? "100%" : size.width,
                            height: editor.isEditable ? "100%" : size.height,
                            border: selected
                                ? "2px solid var(--accent) !important"
                                : "2px solid transparent !important",
                            borderRadius: "default"
                        }, onDoubleClick: () => {
                            var _a, _b;
                            const { hash, filename, mime, size } = node.attrs;
                            if (!!hash && !!filename && !!mime && !!size)
                                (_b = (_a = editor.storage).previewAttachment) === null || _b === void 0 ? void 0 : _b.call(_a, {
                                    type: "image",
                                    hash,
                                    filename,
                                    mime,
                                    size
                                });
                        }, onLoad: function onLoad() {
                            return __awaiter(this, void 0, void 0, function* () {
                                var _a;
                                if (!imageRef.current)
                                    return;
                                const { naturalWidth, naturalHeight, clientHeight, clientWidth } = imageRef.current;
                                const originalWidth = naturalWidth || clientWidth;
                                const originalHeight = naturalHeight || clientHeight;
                                const naturalAspectRatio = originalWidth / originalHeight;
                                const fixedDimensions = fixAspectRatio((_a = size.width) !== null && _a !== void 0 ? _a : originalWidth, naturalAspectRatio);
                                if (src && !DataURL.isValid(src) && canParse(src)) {
                                    const image = yield downloadImage(src, Object.assign(Object.assign({}, downloadOptions), { signal: controllerRef.current.signal })).catch(console.error);
                                    if (!image || !imageRef.current)
                                        return;
                                    const { url, size, blob, mimeType } = image;
                                    imageRef.current.src = url;
                                    const dataurl = yield toDataURL(blob);
                                    yield editor.threadsafe((editor) => editor.commands.updateAttachment(Object.assign(Object.assign({}, fixedDimensions), { src: dataurl, size: size, mime: mimeType, aspectRatio: naturalAspectRatio }), { query: makeImageQuery(src, hash) }));
                                }
                                else if (!aspectRatio || aspectRatio != naturalAspectRatio) {
                                    yield editor.threadsafe((editor) => editor.commands.updateAttachment(Object.assign(Object.assign({}, fixedDimensions), { aspectRatio: naturalAspectRatio }), { query: makeImageQuery(src, hash), ignoreEdit: true }));
                                }
                                else if (size.height !== fixedDimensions.height) {
                                    yield editor.threadsafe((editor) => editor.commands.updateAttachment(fixedDimensions, {
                                        query: makeImageQuery(src, hash),
                                        ignoreEdit: true
                                    }));
                                }
                            });
                        } }))] }) }) }));
}
function makeImageQuery(src, hash) {
    return (a) => a.type === "image" &&
        ((!!a.src && !!src && a.src === src) ||
            (!!a.hash && !!hash && a.hash === hash));
}
function canParse(src) {
    if (!src)
        return false;
    try {
        return !!new URL(src);
    }
    catch (_a) {
        return false;
    }
}
function clampSize(size, maxWidth, aspectRatio) {
    if (typeof aspectRatio === "string" && isNaN(aspectRatio))
        aspectRatio = 1;
    // if no size we set the image to maximum size.
    if (!size.width || !size.height)
        return { width: maxWidth, height: maxWidth };
    if (!aspectRatio)
        aspectRatio = size.width / size.height;
    if (size.width > maxWidth)
        return { width: maxWidth, height: maxWidth / aspectRatio };
    return {
        height: size.height,
        width: size.width
    };
}
function fixAspectRatio(width, aspectRatio) {
    return {
        width,
        height: width / aspectRatio
    };
}
function getAlignmentStyles(options) {
    const { align, float } = options;
    if (float && align !== "center") {
        return {
            ml: align === "right" ? 2 : 0,
            mr: align === "left" ? 2 : 0,
            float: align,
            justifyContent: "stretch"
        };
    }
    return {
        display: "flex",
        justifyContent: align === "center" ? "center" : align === "right" ? "end" : "start"
    };
}
