import { assertExists } from '@blockeditor/global/utils';
import { Buffer } from 'buffer';
import { humanFileSize } from '../_common/utils/math.js';
import { toast } from './../_common/components/toast.js';
import { downloadBlob } from './../_common/utils/filesys.js';
import { buildPath } from './../_common/utils/query.js';
import { ImageBlockModel } from './image-model.js';
async function getImageBlob(model) {
    const blob = await getBlobByModel(model);
    if (!blob)
        return null;
    if (!blob.type) {
        // FIXME: See https://github.com/toeverything/AFFiNE/issues/3245
        // https://github.com/toeverything/AFFiNE/pull/4845
        // https://github.com/toeverything/blockeditor/issues/5097
        // @ts-ignore
        const FileType = await import('file-type/browser.js');
        if (window.Buffer === undefined) {
            window.Buffer = Buffer;
        }
        const buffer = await blob.arrayBuffer();
        const fileType = await FileType.fromBuffer(buffer);
        if (!fileType?.mime.match(/^image\/(gif|png|jpe?g)$/))
            return null;
        return new Blob([buffer], { type: fileType.mime });
    }
    return blob;
}
function convertToString(blob) {
    return new Promise(resolve => {
        const reader = new FileReader();
        reader.addEventListener('load', _ => resolve(reader.result));
        reader.addEventListener('error', () => resolve(null));
        reader.readAsDataURL(blob);
    });
}
function convertToPng(blob) {
    return new Promise(resolve => {
        const reader = new FileReader();
        reader.addEventListener('load', _ => {
            const img = new Image();
            img.onload = () => {
                const c = document.createElement('canvas');
                c.width = img.width;
                c.height = img.height;
                const ctx = c.getContext('2d');
                assertExists(ctx);
                ctx.drawImage(img, 0, 0);
                c.toBlob(resolve, 'image/png');
            };
            img.onerror = () => resolve(null);
            img.src = reader.result;
        });
        reader.addEventListener('error', () => resolve(null));
        reader.readAsDataURL(blob);
    });
}
export async function copyImage(editorHost, model) {
    let blob = await getImageBlob(model);
    if (!blob)
        return;
    try {
        // @ts-ignore
        if (window.apis?.clipboard?.copyAsImageFromString) {
            const dataURL = await convertToString(blob);
            if (!dataURL)
                throw new Error('Cant convert a blob to data URL.');
            // @ts-ignore
            await window.apis.clipboard?.copyAsImageFromString(dataURL);
        }
        else {
            // DOMException: Type image/jpeg not supported on write.
            if (blob.type !== 'image/png') {
                blob = await convertToPng(blob);
            }
            if (!blob)
                return;
            await navigator.clipboard.write([
                new ClipboardItem({ [blob.type]: blob }),
            ]);
        }
        toast(editorHost, 'Copied image to clipboard');
    }
    catch (err) {
        console.error(err);
    }
}
export async function downloadImage(model) {
    const blob = await getImageBlob(model);
    if (!blob)
        return;
    downloadBlob(blob, 'image');
}
export function focusCaption(editorHost, model) {
    const blockEle = editorHost.view.viewFromPath('block', buildPath(model));
    assertExists(blockEle);
    const dom = blockEle.querySelector('.affine-embed-wrapper-caption');
    dom.classList.add('caption-show');
    dom.focus();
}
async function getBlobByModel(model) {
    assertExists(model.sourceId);
    const store = model.page.blob;
    const blob = await store.get(model.sourceId);
    return blob;
}
export function shouldResizeImage(node, target) {
    return !!(target &&
        target instanceof HTMLElement &&
        node.contains(target) &&
        target.classList.contains('resize'));
}
export async function uploadBlobForImage(editorHost, page, blockId, blob) {
    const isLoading = isImageLoading(blockId);
    if (isLoading) {
        throw new Error('the image is already uploading!');
    }
    setImageLoading(blockId, true);
    const storage = page.blob;
    let sourceId = '';
    let imageBlock = null;
    try {
        imageBlock = page.getBlockById(blockId);
        if (!imageBlock) {
            throw new Error('the attachment model is not found!');
        }
        if (!(imageBlock instanceof ImageBlockModel)) {
            console.error(imageBlock);
            throw new Error('the model is not an image model!');
        }
        sourceId = await storage.set(blob);
    }
    catch (error) {
        console.error(error);
        setImageLoading(blockId, false);
        if (error instanceof Error) {
            toast(editorHost, `Failed to upload attachment! ${error.message || error.toString()}`);
        }
    }
    setImageLoading(blockId, false);
    page.withoutTransact(() => {
        if (imageBlock) {
            page.updateBlock(imageBlock, {
                sourceId,
            });
        }
    });
    return blockId;
}
const imageLoadingMap = new Set();
export function setImageLoading(blockId, loading) {
    if (loading) {
        imageLoadingMap.add(blockId);
    }
    else {
        imageLoadingMap.delete(blockId);
    }
}
export function isImageLoading(blockId) {
    return imageLoadingMap.has(blockId);
}
export function addSiblingImageBlock(editorHost, files, maxFileSize, targetModel, place = 'after') {
    const imageFiles = files.filter(file => file.type.startsWith('image/'));
    const isSizeExceeded = imageFiles.some(file => file.size > maxFileSize);
    if (isSizeExceeded) {
        toast(editorHost, `You can only upload files less than ${humanFileSize(maxFileSize, true, 0)}`);
        return [];
    }
    const imageBlockProps = imageFiles.map(file => ({
        flavour: 'affine:image',
        size: file.size,
    }));
    const page = targetModel.page;
    const blockIds = page.addSiblingBlocks(targetModel, imageBlockProps, place);
    blockIds.map((blockId, index) => void uploadBlobForImage(editorHost, page, blockId, imageFiles[index]));
    return blockIds;
}
export function addImageBlocks(editorHost, files, maxFileSize, page, parent, parentIndex) {
    const imageFiles = files.filter(file => file.type.startsWith('image/'));
    const isSizeExceeded = imageFiles.some(file => file.size > maxFileSize);
    if (isSizeExceeded) {
        toast(editorHost, `You can only upload files less than ${humanFileSize(maxFileSize, true, 0)}`);
        return [];
    }
    const blockIds = imageFiles.map(file => page.addBlock('affine:image', { flavour: 'affine:image', size: file.size }, parent, parentIndex));
    blockIds.map((blockId, index) => void uploadBlobForImage(editorHost, page, blockId, imageFiles[index]));
    return blockIds;
}
//# sourceMappingURL=utils.js.map