export const parseNumberFromString = (value, decimals = 2, allowZero = false) => {

    if (typeof value === 'number') return value;
    if(typeof value === 'string' && value.trim().length === 0) return null;
    if (!value || typeof value !== 'string') return 0;


    /* determine decimal separator */
    const lastDot = value.lastIndexOf('.');
    const lastComma = value.lastIndexOf(',');
    const decimalSeparator = (lastDot > lastComma) ? '.' : ',';
    const hasSeparator = !(lastDot === -1 && lastComma === -1);

    if (hasSeparator) {
        /* remove all digit grouping */
        value = (decimalSeparator === '.') ? value.replace(',', '') : value.replace('.', '');

        /* remove artificial decimal separators */
        const parts = value.split(decimalSeparator);
        value = parts.slice(0, -1).join('') + decimalSeparator + parts[parts.length - 1];
    }

    /* replace ',' with '.' and remove all non-digit characters  */
    const normalizedValue = value.replace(',', '.').replace(/[^0-9.]/g, '');
    const parsed = parseFloat(normalizedValue);

    if(parsed > 10e10)
        return null;

    if (isNaN(parsed)) return null;
    const final = Math.round(parsed * Math.pow(10, decimals)) / Math.pow(10, decimals);
    return (final === 0 && !allowZero) ? null : final;
}

export class UrlSafeBase64 {
    constructor() {
        // Standard Base64 alphabet
        this.base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
        // URL-safe Base64 alphabet (replacing + with - and / with _)
        this.urlSafeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';

        // Create reverse lookup table for decoding
        this.decodeTable = {};
        for (let i = 0; i < this.urlSafeChars.length; i++) {
            this.decodeTable[this.urlSafeChars[i]] = i;
        }
    }

    /**
     * Encode a string to URL-safe Base64
     * @param {string} input - The string to encode
     * @returns {string} URL-safe Base64 encoded string
     */
    encode(input) {
        if (!input) return '';

        // Convert string to bytes
        const bytes = new TextEncoder().encode(input);
        let result = '';
        let i = 0;

        // Process 3 bytes at a time
        while (i < bytes.length) {
            const byte1 = bytes[i++];
            const byte2 = i < bytes.length ? bytes[i++] : 0;
            const byte3 = i < bytes.length ? bytes[i++] : 0;

            const bitmap = (byte1 << 16) | (byte2 << 8) | byte3;

            // Extract 6-bit segments
            const char1 = (bitmap >> 18) & 63;
            const char2 = (bitmap >> 12) & 63;
            const char3 = (bitmap >> 6) & 63;
            const char4 = bitmap & 63;

            // Add characters based on how many bytes we had
            result += this.urlSafeChars[char1];
            result += this.urlSafeChars[char2];
            result += (i - 2) < bytes.length ? this.urlSafeChars[char3] : '=';
            result += (i - 1) < bytes.length ? this.urlSafeChars[char4] : '=';
        }

        return result;
    }

    /**
     * Decode a URL-safe Base64 string
     * @param {string} input - The URL-safe Base64 string to decode
     * @returns {string} Decoded string
     */
    decode(input) {
        if (!input) return '';

        // Remove padding if present
        input = input.replace(/=/g, '');

        // Validate input
        if (!/^[A-Za-z0-9\-_]*$/.test(input)) {
            throw new Error('Invalid URL-safe Base64 string');
        }

        const bytes = [];
        let i = 0;

        // Process 4 characters at a time
        while (i < input.length) {
            const char1 = this.decodeTable[input[i++]] || 0;
            const char2 = i < input.length ? this.decodeTable[input[i++]] || 0 : 0;
            const char3 = i < input.length ? this.decodeTable[input[i++]] || 0 : 0;
            const char4 = i < input.length ? this.decodeTable[input[i++]] || 0 : 0;

            const bitmap = (char1 << 18) | (char2 << 12) | (char3 << 6) | char4;

            // Extract original bytes
            const byte1 = (bitmap >> 16) & 255;
            const byte2 = (bitmap >> 8) & 255;
            const byte3 = bitmap & 255;

            bytes.push(byte1);
            if (i - 3 < input.length) bytes.push(byte2);
            if (i - 2 < input.length) bytes.push(byte3);
        }

        // Convert bytes back to string
        return new TextDecoder().decode(new Uint8Array(bytes));
    }

    /**
     * Encode without padding (optional for URLs)
     * @param {string} input - The string to encode
     * @returns {string} URL-safe Base64 encoded string without padding
     */
    encodeNoPadding(input) {
        return this.encode(input).replace(/=/g, '');
    }

    encodeIds(ids) {
        return this.encodeNoPadding(ids.join(','));
    }

    decodeIds(encodedIds) {
        return this.decode(encodedIds).split(',').map(id => parseInt(id));
    }

    /**
     * Convert standard Base64 to URL-safe Base64
     * @param {string} base64 - Standard Base64 string
     * @returns {string} URL-safe Base64 string
     */
    fromStandardBase64(base64) {
        return base64.replace(/\+/g, '-').replace(/\//g, '_');
    }

    /**
     * Convert URL-safe Base64 to standard Base64
     * @param {string} urlSafeBase64 - URL-safe Base64 string
     * @returns {string} Standard Base64 string
     */
    toStandardBase64(urlSafeBase64) {
        return urlSafeBase64.replace(/-/g, '+').replace(/_/g, '/');
    }
}

export const buildDate = (dateStr, time) => {
    if (!dateStr) return 'unknown';

    const date = new Date(dateStr);

    const year = date.getFullYear();
    const month = (date.getMonth() + 1).toString().padStart(2, '0');
    const day = date.getDate().toString().padStart(2, '0');

    if (!time) return `${year}/${month}/${day}`;

    const hours = date.getHours().toString().padStart(2, '0');
    const minutes = date.getMinutes().toString().padStart(2, '0');
    const seconds = date.getSeconds().toString().padStart(2, '0');
    return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`;

}


