import type { Area } from "react-easy-crop";

import { GRIDDO_ID } from "@ax/constants";

import { toBlob } from "html-to-image";

const formatBytes = (bytes: number | null, decimals = 2) => {
	if (bytes === 0 || bytes === null) return "0 Bytes";

	const k = 1024;
	const dm = decimals < 0 ? 0 : decimals;
	const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];

	const i = Math.floor(Math.log(bytes) / Math.log(k));

	return `${parseFloat((bytes / k ** i).toFixed(dm))} ${sizes[i]}`;
};

const imageToBase64 = (file: any): Promise<string> => {
	return new Promise((resolve, reject) => {
		const reader: any = new FileReader();
		reader.onloadend = () => resolve(reader.result);
		reader.onerror = reject;
		reader.readAsDataURL(file);
	});
};

const getImageFromHtml = async (html: HTMLDivElement, fileName: string): Promise<File | null> => {
	const browserContent = html.querySelector<HTMLElement>(".browser-content");

	if (!browserContent) {
		return null;
	}

	const { height, overflow } = getComputedStyle(browserContent);
	browserContent.style.height = "auto";
	browserContent.style.overflow = "visible";
	const originalHeight = browserContent.clientHeight;

	const elChildren = browserContent.querySelectorAll("*");
	let maxAbsoluteElementHeight = 0;
	[].forEach.call(elChildren, (element: HTMLElement) => {
		const isAbsolutePosition = getComputedStyle(element).position === "absolute";
		const isMaxAbsolutePositionHeight = element.clientHeight > maxAbsoluteElementHeight;
		if (isAbsolutePosition && isMaxAbsolutePositionHeight) {
			maxAbsoluteElementHeight = element.clientHeight;
		}
	});
	if (maxAbsoluteElementHeight) {
		const actualHeight = originalHeight + maxAbsoluteElementHeight;
		browserContent.style.height = `${actualHeight}px`;
	}

	return toBlob(browserContent, { quality: 0.95, pixelRatio: 0.5 })
		.then((imageBlob) => {
			return imageBlob && new File([imageBlob], `${fileName}.png`, { type: "image/png" });
		})
		.finally(() => {
			browserContent.style.height = height;
			browserContent.style.overflow = overflow;
		})
		.catch(() => {
			//console.log(err);
			return null;
		});
};

const getImageFromIFrame = async (html: HTMLDivElement, fileName: string): Promise<File | null> => {
	const frameOBject = html.querySelector<HTMLIFrameElement>(".frame-content");
	const frameContentFirst = frameOBject?.contentWindow?.document.getElementById(GRIDDO_ID)?.firstChild as HTMLElement;
	const frameContentId = frameOBject?.contentWindow?.document.getElementById("griddoFormThumb") as HTMLElement;

	const frameContent = frameContentId || frameContentFirst;

	if (!frameContent) {
		return null;
	}

	const { height } = getComputedStyle(frameContent);
	const fullHeight = frameContent?.scrollHeight;

	frameContent.style.height = fullHeight ? `${fullHeight}px` : "auto";

	return toBlob(frameContent, { quality: 0.95, pixelRatio: 0.5 })
		.then((imageBlob) => {
			return imageBlob && new File([imageBlob], `${fileName}.png`, { type: "image/png" });
		})
		.finally(() => {
			frameContent.style.height = height;
		})
		.catch(() => {
			//console.log(err, "err");
			return null;
		});
};

const createImage = (url: string): Promise<HTMLImageElement> =>
	new Promise((resolve, reject) => {
		const image = new Image();
		image.addEventListener("load", () => resolve(image));
		image.addEventListener("error", (error) => reject(error));
		image.setAttribute("crossOrigin", "anonymous");
		image.src = url;
	});

const getCroppedImg = async (imageSrc: string, pixelCrop: Area): Promise<File> => {
	const image = await createImage(imageSrc);
	const canvas = document.createElement("canvas");
	canvas.width = pixelCrop.width;
	canvas.height = pixelCrop.height;
	const ctx = canvas.getContext("2d");

	if (!ctx) throw new Error("Could not get canvas context");

	ctx.drawImage(
		image,
		pixelCrop.x,
		pixelCrop.y,
		pixelCrop.width,
		pixelCrop.height,
		0,
		0,
		pixelCrop.width,
		pixelCrop.height,
	);

	return new Promise((resolve, reject) => {
		canvas.toBlob(
			(blob) => {
				if (!blob) {
					reject(new Error("Canvas is empty"));
					return;
				}
				resolve(new File([blob], "avatar.jpg", { type: "image/jpeg" }));
			},
			"image/jpeg",
			0.9,
		);
	});
};

export { formatBytes, imageToBase64, getImageFromHtml, getImageFromIFrame, createImage, getCroppedImg };
