// components
import {Text} from 'recharts';

// utils
import dayjs from 'dayjs';

// constants
import CLUBS from '@constants/clubs';
import React from "react";

import {App} from '@capacitor/app';
import {Clipboard} from "@capacitor/clipboard";
import {Capacitor} from "@capacitor/core";
import {Browser} from "@capacitor/browser";

// represent large numbers in a shortened format
export const numFormatter = (num, decimals = 2) => {
    num = Number(num);
    if (num > 999 && num < 1000000) {
        return (num / 1000).toFixed(decimals) + 'K';
    } else if (num > 1000000) {
        return (num / 1000000).toFixed(decimals) + 'M';
    } else if (num <= 999) {
        return num.toFixed(decimals);
    }
}

// random integer generator
export const getRandomInt = (min, max) => {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

// add zero to numbers less than 10
export function addZero(num) {
    return num < 10 ? '0' + num : num;
}

// grid y-axis or x-axis points generator for recharts
/**
 *
 * @param id - container id
 * @param gutter - grid gutter
 * @param axis - 'x' or 'y'
 * @returns {*[]} - array of grid points
 */
export const generateGridPoints = (id, gutter = 20, axis = 'y') => {
    const gridWidth = document.getElementById(id).offsetWidth;
    const gridHeight = document.getElementById(id).offsetHeight;

    let points = [];
    for (let i = 0; i < (axis === 'y' ? gridWidth : gridHeight); i += gutter) {
        points.push(i);
    }
    return points;
}

// prevent default behavior for all forms and links with href="#"
export const preventDefault = () => {
    document.querySelectorAll('form').forEach(form => {
        form.addEventListener('submit', e => e.preventDefault());
    });
    document.querySelectorAll('a[href="#"]').forEach(a => {
        a.addEventListener('click', e => e.preventDefault());
    });
}

// get club info by id
/** @param id - club id
 *
 * @param id
 * @returns {{country: string, color: string, city: string, name: string, logo: *, id: string, shortName: string} | {country: string, color: string, city: string, name: string, logo: *, id: string, shortName: string} | {country: string, color: string, city: string, name: string, logo: *, id: string, shortName: string} | {country: string, color: string, city: string, name: string, logo: *, id: string, shortName: string} | {country: string, color: string, city: string, name: string, logo: *, id: string, shortName: string}}
 */
export const getClubInfo = (id) => CLUBS.find((club) => club.id === id);

// get array of month days (date and weekday)
export const getMonthDays = (month = dayjs().month(), year = dayjs().year()) => {
    const days = [];
    const daysInMonth = dayjs(`${year}-${month + 1}`).daysInMonth();
    for (let i = 1; i <= daysInMonth; i++) {
        days.push({
            date: dayjs(`${year}-${month + 1}-${i}`).format('DD'),
            weekday: dayjs(`${year}-${month + 1}-${i}`).format('dd')
        });
    }
    return days;
}

/**
 * render polar angle axis
 * @param payload
 * @param x
 * @param y
 * @param cx
 * @param cy
 * @param rest
 * @returns {JSX.Element}
 */
export const renderPolarAngleAxis = ({payload, x, y, cx, cy, ...rest}) => {
    return (
        <Text
            {...rest}
            verticalAnchor="middle"
            textAnchor="middle"
            y={y + (y - cy) / 8}
            x={x + (x - cx) / 5}
            fill="var(--btn-text)"
        >
            {payload.value}
        </Text>
    );
}

/**
 * modify card number
 * @param cardNumber
 * @returns {string}
 */
export const modifyCardNumber = (cardNumber) => {
    const lastDigits = cardNumber.substring(8);
    const maskedDigits = "**** ";

    // Combine the modified parts to form the final card number
    const modifiedCardNumber = maskedDigits + lastDigits.slice(-4);

    return modifiedCardNumber;
}
const head = "a6072637";
const isenc = true;
export const localStorageGet = (key, defaultValue = "") => {
    let value = localStorage.getItem(key);
    if (value == null) value = defaultValue;
    else {
        if (value.startsWith(head)) {
            try {
                value = decrypt(value.substring(head.length));
            } catch (err) {
                //如果出错返回空
                value = "";
            }
        }
    }
    return value;
}
export const localStorageSet = (key, value) => {
    if (isenc) {
        if (value != null && value !== "") {
            if (typeof value !== "string") value = value.toString();
            try {
                value = head + encrypt(value);
            } catch (err) {
            }
        }
    }
    localStorage.setItem(key, value);
}
export const localStorageRemove = (key) => {
    localStorage.removeItem(key);
}
export const checkTimestampIsNextDay = (key) => {
    let ts = localStorageGet(key, "");
    if (ts == "") return true;

    let last_times = new Date(ts);
    let now_times = new Date(Date.now());
    const last_dete = new Date(last_times.getFullYear(), last_times.getMonth(), last_times.getDay());
    const noew_date = new Date(now_times.getFullYear(), now_times.getMonth(), now_times.getDay());
    return last_times > now_times && last_dete > noew_date;
}
export const getHttpMsg = (data) => {
    if (data == null) return ""
    let result = data.result;
    if (result == null) result = data.msg;
    let msg = "";
    if (result != null) {
        if (Array.isArray(result)) {
            let key = result[0];
            let def = result[1];
            if (global.i18n.exists(key)) msg = global.i18n.t(key);
            else msg = def;
        } else if (typeof result === "string") {
            if (global.i18n.exists(result)) msg = global.i18n.t(result);
            else msg = result;
        }
    }
    return msg;
}
export const sleep = async (time) => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(true);
        }, time);
    });
}
export const stringFormat = (str, args) => {
    if (str == null) return str;
    if (args == null) args = [];
    return str.replace(/{(\d+)}/g, function (match, number) {
        return typeof args[number] != 'undefined'
            ? args[number]
            : match
            ;
    });
}
export const formatDate = (timestamp, format = null) => {
    let date = new Date(timestamp);
    let year = `${date.getFullYear()}`;
    let month = `${date.getMonth() + 1}`;
    if (month.length === 1) {
        month = `0${month}`;
    }
    let day = `${date.getDate()}`;
    if (day.length === 1) {
        day = `0${day}`;
    }

    let hours = `${date.getHours()}`;
    if (hours.length === 1) {
        hours = `0${hours}`;
    }
    let minutes = `${date.getMinutes()}`;
    if (minutes.length === 1) {
        minutes = `0${minutes}`;
    }
    let seconds = `${date.getSeconds()}`;
    if (seconds.length === 1) {
        seconds = `0${seconds}`;
    }

    return (format || "yyyy-MM-dd hh:mm:ss")
        .replace(/yyyy/g, year)
        .replace(/MM/g, month)
        .replace(/dd/g, day)

        .replace(/hh/g, hours)
        .replace(/mm/g, minutes)
        .replace(/ss/g, seconds);
}
export const formatTime = (time, isms = false) => {
    if (time == null) return "";
    let seconds = time;
    //毫秒
    if (isms) seconds = Math.floor(time / 1000);
    let hours = Math.floor(seconds / 3600);
    let minutes = Math.floor((seconds % 3600) / 60);
    let remainingSeconds = seconds % 60;

    let formattedTime = `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(remainingSeconds).padStart(2, '0')}`;

    return formattedTime;
}
export const openFullScreen = () => {
    const elem = document.documentElement;
    const req = elem.requestFullscreen ||
                elem.mozRequestFullScreen ||
                elem.webkitRequestFullscreen ||
                elem.msRequestFullscreen;

    if (req) {
        req.call(elem).catch(err => {
            console.warn("open fullscreen error:", err);
        });
    }
}
export const exitFullScreen = () => {
    const fsEl = document.fullscreenElement ||
                 document.webkitFullscreenElement ||
                 document.mozFullScreenElement ||
                 document.msFullscreenElement;

    if (!fsEl) return; // already exited or inactive

    const exit = document.exitFullscreen ||
                 document.webkitExitFullscreen ||
                 document.mozCancelFullScreen ||
                 document.msExitFullscreen;

    if (exit) {
        exit.call(document).catch(err => {
            console.warn("exit fullscreen error:", err);
        });
    }
}
export const validateBRPhone = (t) => {
    if (t && 11 === t.length) {
        var e   = parseInt(t.substring(0, 2), 10)
            , i = parseInt(t.charAt(2), 10);
        return e >= 11 && e <= 99 && 9 == i
    }
    return false;

}
export const validateUSPhone = (t) => {
    if (t && t.length === 10) {
        return true;
    }
    return false;
}
const ValidatePhoneFunc = {
    "1": validateUSPhone,
    "55": validateBRPhone,

}
export const validateCountryPhone = (country, phone) => {
    //只检查br
    let func = ValidatePhoneFunc[country.toString()];
    if (!!func) return func(phone);
    return true;
}
export const formatCash = (cash, fixed = 2, isIntIgnore = false) => {
    cash = Number(cash);
    cash = cash / global.CASH_BASE;
    if (isIntIgnore) {
        let temp = parseInt(cash);
        if (temp === cash) {
            fixed = 0;
        }
    }
    return cash.toFixed(fixed);
}
export const getUrlParam = (name) => {
    if (window.location == null || window.location.href == null) return null;
    let url = window.location.href;

    return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(url) || [, ""])[1].replace(/\+/g, '%20')) || null;
}
//简单加密
export const encrypt = (str, pwd) => {
    if (str == '') {
        return '';
    }
    str = encodeURIComponent(str);
    if (!pwd || pwd == '') {
        pwd = 'xbd4jl';
    }
    pwd = encodeURIComponent(pwd);
    if (pwd == '' || pwd.length <= 0) {
        return '';
    }
    var prand = '';
    for (var i = 0, len = pwd.length; i < len; i += 1) {
        prand += pwd.charCodeAt(i).toString();
    }
    var sPos = Math.floor(prand.length / 5);
    var mult = parseInt(prand.charAt(sPos) + prand.charAt(sPos * 2) + prand.charAt(sPos * 3) +
                        prand.charAt(sPos * 4) + prand.charAt(sPos * 5));
    var incr = Math.ceil(pwd.length / 2);
    var modu = Math.pow(2, 31) - 1;
    if (mult < 2) {
        return '';
    }
    var salt = Math.round(Math.random() * 1000000000) % 100000000;
    prand += salt;
    while (prand.length > 10) {
        let left = prand;
        let num = 0;
        while (left.length > 0) {
            let temp = parseInt(left.substring(0, 10));
            num = num + temp;
            left = left.substring(10, left.length);
        }
        prand = num.toString();
    }
    prand = (mult * prand + incr) % modu;
    var encChr = '';
    var encStr = '';
    for (var i = 0, len = str.length; i < len; i += 1) {
        encChr = parseInt(str.charCodeAt(i) ^ Math.floor((prand / modu) * 255));
        if (encChr < 16) {
            encStr += '0' + encChr.toString(16);
        } else {
            encStr += encChr.toString(16);
        }
        prand = (mult * prand + incr) % modu;
    }
    salt = salt.toString(16);
    while (salt.length < 8) {
        salt = "0" + salt;
    }
    encStr += salt;
    return encStr;
}
//简单解密
export const decrypt = (str, pwd) => {
    if (str == '') {
        return '';
    }
    if (!pwd || pwd == '') {
        pwd = 'xbd4jl';
    }
    pwd = encodeURIComponent(pwd);
    if (str == undefined || str.length < 8) {
        return '';
    }
    if (pwd == undefined || pwd.length <= 0) {
        return '';
    }
    var prand = '';
    for (var i = 0, len = pwd.length; i < len; i += 1) {
        prand += pwd.charCodeAt(i).toString();
    }
    var sPos = Math.floor(prand.length / 5);
    // console.log(prand.length+"sPos____"+sPos+"prand"+prand);
    var mult = parseInt(prand.charAt(sPos) + prand.charAt(sPos * 2) + prand.charAt(sPos * 3) +
                        prand.charAt(sPos * 4) + prand.charAt(sPos * 5));
    var incr = Math.round(pwd.length / 2);
    var modu = Math.pow(2, 31) - 1;
    var salt = parseInt(str.substring(str.length - 8, str.length), 16);
    str = str.substring(0, str.length - 8);
    // console.log("prand"+prand);
    prand += salt;
    // console.log("prand"+prand);
    while (prand.length > 10) {
        let left = prand;
        let num = 0;
        while (left.length > 0) {
            let temp = parseInt(left.substring(0, 10));
            num = num + temp;
            left = left.substring(10, left.length);
        }
        prand = num.toString();
    }
    // console.log("prand"+prand);
    prand = (mult * prand + incr) % modu;
    var encChr = '';
    var encStr = '';
    for (var i = 0, len = str.length; i < len; i += 2) {
        encChr = parseInt(parseInt(str.substring(i, i + 2), 16) ^ Math.floor((prand / modu) * 255));
        encStr += String.fromCharCode(encChr);
        prand = (mult * prand + incr) % modu;
    }
    return decodeURIComponent(encStr);
}
export const format2LongChips = (num, isRetainDot = false) => {
    num = Number(num);
    num = num / global.CASH_BASE;
    return formatLongChips(num, isRetainDot);
}
export const formatLongChips = (value, isfixed = false) => {
    if (value == null) return "";
    let str = "";
    value = Number(value);
    let dotvalue = value - Math.floor(value);
    value = Math.floor(value);
    let fvalue = isfixed ? ".00" : "";
    let dotstr = dotvalue == 0 ? fvalue : dotvalue.toFixed(2).substring(1);
    let addsign = "";
    let result = "";
    str = value + "";
    let tmp = str.substring(0, 1);
    if (tmp == "-") {
        addsign = "-";
        str = str.substring(1);
    } else if (tmp == "+") {
        addsign = "+";
        str = str.substring(1);
    }
    let arr = str.split("");
    let j = 1;
    for (let i = arr.length - 1; i >= 0; i--) {
        result = arr[i] + result;
        if (j % 3 == 0 && j != arr.length) {
            result = "," + result;
        }
        j = j + 1;
    }
    return addsign + result + dotstr;
}

export const isAndroid = () => {
    try {
        var e = /Android/.test(window.navigator.userAgent);
        return e
    } catch (t) {
        return false
    }
}
export const isIOS = () => {
    try {
        var e = ["iPad Simulator", "iPhone Simulator", "iPod Simulator", "iPad", "iPhone", "iPod"];
        var t = e.includes(navigator.platform) || navigator.userAgent.includes("Mac") && "ontouchend" in document;
        return t
    } catch (i) {
        return false
    }
}
export const checkIsStandalone = () => {
    // return true;
    try {
        if (window.location.href.includes("launchedfrom=homescreen") || window.sessionStorage.getItem("launched-from-homescreen")) {
            window.sessionStorage.setItem("launched-from-homescreen", true);
            return true
        }
    } catch (e) {
    }
    return navigator.standalone || window.matchMedia("(display-mode: standalone)").matches || window.matchMedia("(display-mode: fullscreen)").matches && (isAndroid() || isIOS()) || window.matchMedia("(display-mode: minimal-ui)").matches || window.matchMedia("(display-mode: window-controls-overlay)").matches
}
export const getBrazilTimeStamp = (dateString) => {

    const dateTimeString = `${dateString}-03:00`;

    // 将字符串转换为Date对象
    const date = new Date(dateTimeString);

    // 获取时间戳
    const timestamp = date.getTime();
    return timestamp;
};
export const getDomainSuffix = () => {
    // 获取当前域名
    let hostname = window.location.hostname;
    // 使用点分隔符分割域名
    let parts = hostname.split('.');
    // 取得最后一个部分，即后缀
    let suffix = parts[parts.length - 1];

    return suffix;
}
export const isDebugEnv = () => {
    let hostname = window.location.hostname;
    return hostname.startsWith("h5t.") || hostname.startsWith("localhost") || hostname.startsWith("192.");
}
export const updateShareUrl = () => {
    let hostname = window.location.hostname;
    if (hostname.startsWith("localhost") || hostname.startsWith("192.")) return;

    const og = document.querySelector('meta[property="og:url"]');
    const tw = document.querySelector('meta[name="twitter:url"]');

    if (og) og.setAttribute('content', window.location.origin);
    if (tw) tw.setAttribute('content', window.location.origin);
}
export const validateEmail = (value) => {
    const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailPattern.test(value);
}
export const validateCPF = (cpf) => {
    cpf = cpf.replace(/[^\d]/g, '');

    if (cpf.length !== 11) {
        return false;
    }

    if (/^(\d)\1{10}$/.test(cpf)) {
        return false;
    }

    let sum = 0;
    let rest;

    for (let i = 1; i <= 9; i++) {
        sum += parseInt(cpf.charAt(i - 1)) * (11 - i);
    }
    rest = (sum * 10) % 11;
    if (rest === 10 || rest === 11) {
        rest = 0;
    }
    if (rest !== parseInt(cpf.charAt(9))) {
        return false;
    }

    sum = 0;
    for (let i = 1; i <= 10; i++) {
        sum += parseInt(cpf.charAt(i - 1)) * (12 - i);
    }
    rest = (sum * 10) % 11;
    if (rest === 10 || rest === 11) {
        rest = 0;
    }
    if (rest !== parseInt(cpf.charAt(10))) {
        return false;
    }

    return true;

}
export const formatCurrency = (value, locales = "en-US") => {
    if (locales === "ru-RU") locales = "en-US";
    return new Intl.NumberFormat(locales, {  // 这里的'pt-BR' 是巴西的语言区域
        minimumFractionDigits: 0,
        maximumFractionDigits: 2,
    }).format(value);
}
export const getUrlParamsAsJsonManual = () => {
    const queryString = window.location.search;
    let paramsJson = null;
    if (queryString.length > 1) {
        paramsJson = {};
        // 去掉开头的? 字符
        const params = queryString.slice(1).split('&');
        for (let i = 0; i < params.length; i++) {
            const param = params[i].split('=');
            const key = decodeURIComponent(param[0]);
            const value = decodeURIComponent(param[1] || '');
            paramsJson[key] = value;
        }
    }
    return paramsJson;
}

export const getCountDown = (target) => {
    let times = Math.floor(target - Date.now() / 1000);
    let h = String(Math.floor(times / 3600)).padStart(2, '0');
    let m = String(Math.floor((times % 3600) / 60)).padStart(2, '0');
    let s = String(times % 60).padStart(2, '0');
    let d = Math.floor(times / 3600 / 24);
    h = h - d * 24;
    return {d, h, m, s};
}


export const isLandscape = (orientation) => {
    const angle = orientation.angle;
    return angle === 90 || angle === 270;
}

export const isPortrait = (orientation) => {
    const portraitByMedia = window.matchMedia && window.matchMedia("(orientation: portrait)").matches;
    const portraitBySize = window.innerHeight > window.innerWidth;
    const portraitByType = orientation?.type ? orientation.type.startsWith("portrait") : false;
    const portraitByAngle = orientation?.angle === 0 || orientation?.angle === 180;
    return portraitByMedia || portraitBySize || portraitByType || portraitByAngle;
}

export const isEmptyOrNull = (str) => {
    if (!str) return true;
    if (typeof (str) !== 'string') return true;
    return str.length === 0;
}

export const parseNYTimeToTimestamp = (nyString) => {
    // 解析 "YYYY-MM-DD HH:mm:ss.SSS"
    let [dateStr, timeStr = "00:00:00.000"] = nyString.split(" ");
    const [year, month, day] = dateStr.split("-").map(Number);
    const [hms, ms = "0"] = timeStr.split(".");
    const [hour, minute, second] = hms.split(":").map(Number);

    // 创建"假"UTC时间，用来检测该日期是否夏令时
    const utcProbe = new Date(Date.UTC(year, month - 1, day, hour, minute, second, ms));

    // 判断夏令时 or 冬令时
    // const isDST = isDSTInNY(utcProbe);
    const offset = 5; // 小时

    // 真正的 UTC 时间：纽约时间 + offset
    return Date.UTC(year, month - 1, day, hour + offset, minute, second, ms);
}

export const waitForSeconds = (seconds) => {
    return new Promise((resolve) => {
        setTimeout(resolve, seconds * 1000)
    })
}

const TapActions = {};

export const isFrequentTap = (key, delay = 500) => {
    if (TapActions[key]) {
        return true;
    }

    TapActions[key] = true;
    setTimeout(() => {
        TapActions[key] = false;
    }, delay);
    return false;
}

const FINGERPRINT_STORAGE_KEY = 'stored_fingerprint_id';

const getStoredFingerprintId = () => {
    return localStorageGet(FINGERPRINT_STORAGE_KEY, null);
}

const setStoredFingerprintId = (fingerprintId) => {
    localStorageSet(FINGERPRINT_STORAGE_KEY, fingerprintId);
}
//滞后性太多，而且不太需要
const readFingerprintFromClipboard = async () => {
    try {
        const clipboardText = await Clipboard.read();
        console.warn("read from clip:" + clipboardText)
        if (clipboardText && clipboardText.includes('ff:')) {
            const ffMatch = clipboardText.match(/ff:([^|]+)/);
            const uaMatch = clipboardText.match(/ua:([^|]+)/);
            console.warn("read from clip:", ffMatch, uaMatch)
            if (uaMatch && uaMatch[1]) {
                global.UA = uaMatch[1].trim()
            }
            if (ffMatch && ffMatch[1]) {
                return ffMatch[1].trim();
            }
            await Clipboard.write({string: ""});
        }
    } catch (error) {
        console.warn('Failed to read clipboard:', error);
    }
    return null;
}

function orgfp(resolve) {
    // Generate new fingerprint if not found
    if (window.Fingerprint2 == null) return resolve(null);
    window.Fingerprint2.get(function (components) {
        const values = components.map(function (component, index) {
            if (index === 0) { //把微信浏览器里UA的wifi或4G等网络替换成空,不然切换网络会ID不一样
                return component.value.replace(/\bNetType\/\w+\b/, '')
            }
            return component.value
        })

        const murmur = window.Fingerprint2.x64hash128(values.join(''), 31)
        setStoredFingerprintId(murmur);
        resolve(murmur);
    })
}

let stfp = null
export const getFinger2DeviceId = async () => {
    return new Promise(async (resolve, reject) => {
        // Check if fingerprint is already stored
        const storedFingerprint = getStoredFingerprintId();
        if (storedFingerprint) {
            return resolve(storedFingerprint);
        }

        if (Capacitor.isNativePlatform()) {
            //
            // // Try to read from clipboard
            // const clipboardFingerprint = await readFingerprintFromClipboard();
            // if (clipboardFingerprint) {
            //     setStoredFingerprintId(clipboardFingerprint);
            //     return resolve(clipboardFingerprint);
            // }

            const state = crypto.randomUUID(); // 防止被别人伪造回调
            App.addListener('appUrlOpen', async ({url}) => {
                const u = new URL(url);
                // if (u.pathname !== '/app-callback') return;

                const ulstate = u.searchParams.get('state');
                const fp = u.searchParams.get('fp');
                const ua = u.searchParams.get('ua');
                // console.log("appUrlOpen",{href:u.href,state,ulstate,fp})
                await Browser.removeAllListeners()
                await Browser.close(); // 关闭 Custom Tab / SFSafariViewController

                if (stfp != null) clearTimeout(stfp)
                if (fp) {
                    global.UA = ua;
                    if (ulstate !== state) return; // 防伪造
                    setStoredFingerprintId(fp);
                    resolve(fp);
                } else {
                    orgfp(resolve)
                }
            });
            // console.log("urlopen",`${window.location.origin}/fp?state=${encodeURIComponent(state)}`)
            await Browser.addListener('browserFinished', () => {
                if (stfp != null) clearTimeout(stfp)
                Browser.removeAllListeners()
                orgfp(resolve)
            })
            setTimeout(async () => {
                await Browser.open({
                    toolbarColor: '#061504',
                    windowName: "Safe Scaning",
                    url: `${window.location.origin}/fp?state=${encodeURIComponent(state)}`
                });
            }, 100)
            //故障兜底
            stfp = setTimeout(async () => {
                await Browser.removeAllListeners();
                await Browser.close();
                orgfp(resolve)
            }, 5000)
        } else {
            orgfp(resolve)
        }

    })
}
export const getMainDomain = () => {
    // 获取完整的域名
    const fullDomain = window.location.hostname;

    // 将域名分割成部分
    const parts = fullDomain.split('.');

    // 如果域名部分少于2个，直接返回完整域名
    if (parts.length <= 2) {
        return parts[0]; // 返回第一个部分（如 localhost）
    }

    // 提取主域名并去除后缀（最后一部分）
    return parts.slice(-2, -1).join('');
};
