/**
 * Copyright schukai GmbH and contributors 2023. All Rights Reserved.
 * Node module: @schukai/monster
 * This file is licensed under the AGPLv3 License.
 * License text available at https://www.gnu.org/licenses/agpl-3.0.en.html
 */

import { getWindow } from "./util.mjs";

export { convertToPixels, getDeviceDPI };

/**
 * Stores the DPI of the device.
 *
 * @private
 * @returns {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
 * @memberOf Monster.DOM
 * @returns {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]
 * @returns {number}
 * @license AGPLv3
 * @since 3.34.0
 * @copyright schukai GmbH
 * @throws {Error} Unsupported unit
 * @memberOf Monster.DOM
 * @throws {Error} Invalid value format
 */

function convertToPixels(value, parentElement = document.documentElement, fontSizeElement = document.documentElement) {
    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}`);
    }
}