/**
 * Copyright © Volker Schukai and all contributing authors, {{copyRightYear}}. All rights reserved.
 * Node module: @schukai/monster
 *
 * This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3).
 * The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html
 *
 * For those who do not wish to adhere to the AGPLv3, a commercial license is available.
 * Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms.
 * For more information about purchasing a commercial license, please contact Volker Schukai.
 *
 * SPDX-License-Identifier: AGPL-3.0
 */

import { getWindow } from "./util.mjs";
import { validateString } from "../types/validate.mjs";

export { convertToPixels, getDeviceDPI };

/**
 * Stores the DPI of the device.
 *
 * @private
 * @return {number}
 * @since 3.34.0
 * @type {number|function}
 */
let CURRENT_DEVICE_DPI = function () {
	let i = 0;
	for (i = 56; i < 2000; i++) {
		if (getWindow().matchMedia(`(max-resolution: ${i}dpi)`).matches === true) {
			return i;
		}
	}
	return i;
};

/**
 * Returns the DPI of the device.
 *
 * @since 3.34.0
 * @return {number}
 */
function getDeviceDPI() {
	// only call the function once
	if (typeof CURRENT_DEVICE_DPI === "function") {
		CURRENT_DEVICE_DPI = CURRENT_DEVICE_DPI();
	}

	return getWindow().devicePixelRatio * CURRENT_DEVICE_DPI;
}

/**
 * Converts a CSS value to pixels.
 *
 * As Example:
 *
 * ```js
 * convertToPixels('1em') // returns the current font size in pixels
 * convertToPixels('1rem') // returns the current root font size in pixels
 * convertToPixels('1px') // returns 1
 * convertToPixels('100%') // returns the current width of the parent element in pixels
 * ```
 *
 * Following units are supported:
 * - px
 * - em
 * - rem
 * - %
 *
 * @param {string} value
 * @param {HTMLElement} [parentElement=document.documentElement]
 * @param {HTMLElement} [fontSizeElement=document.documentElement]
 * @return {number}
 * @license AGPLv3
 * @since 3.34.0
 * @copyright Volker Schukai
 * @throws {Error} Unsupported unit
 * @throws {Error} Invalid value format
 */

function convertToPixels(
	value,
	parentElement = document.documentElement,
	fontSizeElement = document.documentElement,
) {
	validateString(value);

	const regex = /^(-?[\d.]+)(.*)$/;
	const matchResult = value.match(regex);

	if (!matchResult) {
		throw new Error(`Invalid value format: ${value}`);
	}

	const [, num, unit] = matchResult;
	const number = parseFloat(num);
	const dpi = getDeviceDPI();

	if (unit === "px") {
		return number;
	} else if (unit === "em") {
		const fontSize = parseFloat(
			window.getComputedStyle(fontSizeElement).fontSize,
		);
		return number * fontSize;
	} else if (unit === "rem") {
		const rootFontSize = parseFloat(
			window.getComputedStyle(parentElement).fontSize,
		);
		return number * rootFontSize;
	} else if (unit === "%") {
		const parentWidth = parseFloat(
			window.getComputedStyle(parentElement).width,
		);
		return (number * parentWidth) / 100;
	} else if (unit === "in") {
		return number * dpi;
	} else if (unit === "cm") {
		return (number * dpi) / 2.54;
	} else if (unit === "mm") {
		return (number * dpi) / 25.4;
	} else if (unit === "pt") {
		return (number * dpi) / 72;
	} else if (unit === "pc") {
		return (number * dpi) / 6;
	} else {
		throw new Error(`Unsupported unit: ${unit}`);
	}
}
