// 假设 CommonParames 和 TradeLogger 等类在其他文件中定义
// 这里简单模拟一下
class CommonParames {
    static Coding = 'utf-8';
    static MsgErrorMap: { [key: string]: string } = {};
}

class TradeLogger {
    static Error(error: any) {
        console.error(error);
    }
}

// 假设 IPage 接口在其他文件中定义
interface IPage {}

// 假设 FilesHandle 类在其他文件中定义
class FilesHandle {
    static GetFileData(fileName: string): Uint8Array {
        // 这里只是模拟实现，实际需要根据具体情况实现
        return new Uint8Array();
    }
    static SaveFileData(fileName: string, fileData: Uint8Array, append: boolean): boolean {
        // 这里只是模拟实现，实际需要根据具体情况实现
        return true;
    }
}

// 假设 ComboBox 类在其他文件中定义
class ComboBox {
    SetItems(dict: { [key: string]: string }) {}
    FontSize = 12;
    MinWidth = 0;
}

// 定义 ScriptFunction 类
class ScriptFunction {
    // 字符串数字处理类

    /**
     * 将数字串转换成整数
     * @param number 数字串
     * @returns 整数
     */
    static Atoi(number: string): number {
        return parseInt(number, 10);
    }

    /**
     * 将数字串转换成整数
     * @param target 
     * @param number 数字串
     * @returns 整数
     */
    static AtoiPage(target: IPage, number: string): number {
        return ScriptFunction.Atoi(number);
    }

    /**
     * 将数字按指定格式格式化为字符串 暂时支持%d %f这两大类
     * @param number 数字
     * @param format 格式
     * @returns 格式化后的字符串
     */
    static Itoa(number: number, format: string): string {
        const rgx = /^%{1}(-)?(([0-9]*)[dD]{1})|(([0-9]*)(.)?([0-9]*)[fF]{1})$/;
        if (!rgx.test(format)) {
            throw new Error('不支持该格式转换！');
        }

        let outdata = '';
        let width = -1;
        let sindex = 0;
        let eindex = 0;
        let signindex = format.includes('-') ? format.indexOf('-') : -1;
        let dotindex = -1;
        let formatparse = format;
        let hasZero = false;

        if (signindex === -1) {
            if (format.substring(1, 2) === '0') {
                formatparse = format.substring(0, 1) + format.substring(2);
                hasZero = true;
            }
        } else {
            if (format.substring(2, 3) === '0') {
                formatparse = format.substring(0, 2) + format.substring(3);
                hasZero = true;
            }
        }

        if (formatparse === '' || formatparse.includes('d') || formatparse.includes('D')) {
            eindex = formatparse.includes('d') ? formatparse.indexOf('d') : formatparse.indexOf('D');
            outdata = number.toFixed(0);
        }

        if (formatparse.includes('f') || formatparse.includes('F')) {
            dotindex = formatparse.indexOf('.');
            eindex = formatparse.includes('f') ? formatparse.indexOf('f') : formatparse.indexOf('F');

            if (dotindex === -1) {
                outdata = number.toFixed(0);
            } else {
                if (eindex - dotindex === 1) {
                    outdata = number.toFixed(0);
                } else {
                    outdata = number.toFixed(parseInt(formatparse.substring(dotindex + 1, eindex), 10));
                }
            }
        }

        if (dotindex === -1) {
            if (signindex === -1) {
                width = eindex - sindex === 1 ? -1 : parseInt(formatparse.substring(sindex + 1, eindex), 10);
            } else {
                width = eindex - signindex === 1 ? -1 : parseInt(formatparse.substring(signindex + 1, eindex), 10);
            }
        } else {
            if (signindex === -1) {
                width = dotindex - sindex === 1 ? -1 : parseInt(formatparse.substring(sindex + 1, dotindex), 10);
            } else {
                width = dotindex - signindex === 1 ? -1 : parseInt(formatparse.substring(signindex + 1, dotindex), 10);
            }
        }

        if (width === -1) {
            return outdata;
        } else {
            if (outdata.length >= width) {
                return outdata;
            } else {
                if (signindex === -1) {
                    if (hasZero) {
                        return outdata.padStart(width, '0');
                    } else {
                        return outdata.padStart(width);
                    }
                } else {
                    if (hasZero) {
                        return outdata.padEnd(width, '0');
                    } else {
                        return outdata.padEnd(width);
                    }
                }
            }
        }
    }

    /**
     * 将数字按指定格式格式化为字符串 暂时支持%d %f这两大类
     * @param target 
     * @param number 数字
     * @param format 格式
     * @returns 格式化后的字符串
     */
    static ItoaPage(target: IPage, number: number, format: string): string {
        return ScriptFunction.Itoa(number, format);
    }

    /**
     * 截取子字符串
     * @param sourceData 源字符串
     * @param start 起始index
     * @param length 截取长度
     * @returns 截取后的字符串
     */
    static SubStr(sourceData: string, start: number, length: number): string {
        const dataBytes = new TextEncoder().encode(sourceData);
        if (length > dataBytes.length - start) {
            length = dataBytes.length - start;
        }
        const tmpBytes = dataBytes.slice(start, start + length);
        return new TextDecoder(CommonParames.Coding).decode(tmpBytes);
    }

    /**
     * 截取子字符串
     * @param target 
     * @param sourceData 源字符串
     * @param start 起始
     * @param length 截取长度
     * @returns 截取后的字符串
     */
    static SubStrPage(target: IPage, sourceData: string, start: number, length: number): string {
        return ScriptFunction.SubStr(sourceData, start, length);
    }

    /**
     * 内部函数，取得字符串长度
     * @param sourceData 源字符串
     * @returns 字符串长度
     */
    static Len(sourceData: string): number {
        return new TextEncoder().encode(sourceData).length;
    }

    /**
     * 取得字符串长度
     * @param target 
     * @param sourceData 源数据
     * @returns 长度
     */
    static LenPage(target: IPage, sourceData: string): number {
        return ScriptFunction.Len(sourceData);
    }

    /**
     * 将ASCII码值转换为字符串
     * @param number ASCII码值
     * @returns 字符串
     */
    static Chr(number: number): string {
        return String.fromCharCode(number);
    }

    /**
     * 将ASCII码值转换为字符串
     * @param target 
     * @param number ASCII码值
     * @returns 字符串
     */
    static ChrPage(target: IPage, number: number): string {
        return ScriptFunction.Chr(number);
    }

    /**
     * 求两个整数的余
     * @param number1 被除数
     * @param number2 除数
     * @returns 余数
     */
    static Mod(number1: number, number2: number): number {
        return number1 % number2;
    }

    /**
     * 求两个整数的余
     * @param target 
     * @param number1 被除数
     * @param number2 除数
     * @returns 余数
     */
    static ModPage(target: IPage, number1: number, number2: number): number {
        return ScriptFunction.Mod(number1, number2);
    }

    /**
     * 将数字串转换成千分位方式显示
     * @param sourceData 处理前数据
     * @param length 指定长度
     * @returns 处理后数据
     */
    static Comma(sourceData: string, length: number): string {
        let result: number;
        if (!Number.isNaN(result = parseFloat(sourceData))) {
            const exception = new Error(
                `Comma函数执行出错！[${sourceData}]不是有效的数字类型！`
            );
            TradeLogger.Error(exception);
            throw exception;
        }
        return result.toLocaleString('zh-CN', { style: 'currency', currency: 'CNY' }).padStart(length);
    }

    /**
     * 将数字串转换成千分位方式显示
     * @param target 
     * @param sourceData 处理前数据
     * @param length 指定长度
     * @returns 处理后数据
     */
    static CommaPage(target: IPage, sourceData: string, length: number): string {
        return ScriptFunction.Comma(sourceData, length);
    }

    /**
     * 左补齐参数字符
     * @param sourcedata 源字符串
     * @param length 补齐长度
     * @param var 参数字符
     * @returns 补齐后的字符串
     */
    static PadLeft(sourcedata: string, length: number, varChar = ' '): string {
        const data = new TextEncoder().encode(sourcedata);
        const len = length - data.length;
        if (len > 0) {
            return sourcedata.padStart(sourcedata.length + len, varChar);
        }
        return sourcedata;
    }

    /**
     * 左补齐参数字符
     * @param target 
     * @param sourcedata 源字符串
     * @param length 补齐长度
     * @param var 参数字符
     * @returns 补齐后的字符串
     */
    static PadLeftPage(target: IPage, sourcedata: string, length: number, varChar = ' '): string {
        return ScriptFunction.PadLeft(sourcedata, length, varChar);
    }

    /**
     * 右补齐参数字符
     * @param sourcedata 源字符串
     * @param length 补齐长度
     * @param var 参数字符
     * @returns 补齐后的字符串
     */
    static PadRight(sourcedata: string, length: number, varChar = ' '): string {
        const data = new TextEncoder().encode(sourcedata);
        const len = length - data.length;
        if (len > 0) {
            return sourcedata.padEnd(sourcedata.length + len, varChar);
        }
        return sourcedata;
    }

    /**
     * 右补齐参数字符
     * @param target 
     * @param sourcedata 源字符串
     * @param length 补齐长度
     * @param var 参数字符
     * @returns 补齐后的字符串
     */
    static PadRightPage(target: IPage, sourcedata: string, length: number, varChar = ' '): string {
        return ScriptFunction.PadRight(sourcedata, length, varChar);
    }

    /**
     * 数字串（十进制或十六进制）与权重相乘
     * @param sourceData 数字串
     * @param weight 权重
     * @returns 结果
     */
    static Val(sourceData: string, weight: number): number {
        let result: number;
        if (!Number.isNaN(result = parseFloat(sourceData))) {
            const exception = new Error(
                `Val函数执行出错！[${sourceData}]不是有效的数字类型！`
            );
            TradeLogger.Error(exception);
            throw exception;
        }
        return result * weight;
    }

    /**
     * 数字串（十进制或十六进制）与权重相乘
     * @param target 
     * @param sourceData 数字串
     * @param weight 权重
     * @returns 结果
     */
    static ValPage(target: IPage, sourceData: string, weight: number): number {
        return ScriptFunction.Val(sourceData, weight);
    }

    /**
     * 去除字符串后面空格
     * @param sourceData 源数据
     * @returns 处理后数据
     */
    static RTrim(sourceData: string): string {
        return sourceData.trimEnd();
    }

    /**
     * 去除字符串后面空格
     * @param target 
     * @param sourceData 源数据
     * @returns 处理后数据
     */
    static RTrimPage(target: IPage, sourceData: string): string {
        return ScriptFunction.RTrim(sourceData);
    }

    /**
     * 去除字符串开始空格
     * @param sourceData 源数据
     * @returns 处理后数据
     */
    static LTrim(sourceData: string): string {
        return sourceData.trimStart();
    }

    /**
     * 去除字符串开始空格
     * @param target 
     * @param sourceData 源数据
     * @returns 处理后数据
     */
    static LTrimPage(target: IPage, sourceData: string): string {
        return ScriptFunction.LTrim(sourceData);
    }

    /**
     * 以某个字符构建某长度的字符串
     * @param lenght 长度
     * @param c 字符
     * @returns 构建后的字符串
     */
    static Space(lenght: number, c = ' '): string {
        return new Array(lenght).fill(c).join('');
    }

    /**
     * 以某个字符构建某长度的字符串
     * @param target 
     * @param lenght 长度
     * @param c 字符
     * @returns 构建后的字符串
     */
    static SpacePage(target: IPage, lenght: number, c = ' '): string {
        return ScriptFunction.Space(lenght, c);
    }

    /**
     * 内部函数，去掉空格
     * @param sourceData 源数据
     * @returns 处理后数据
     */
    static Delspace(sourceData: string): string {
        return sourceData.trim().replace(/\0/g, '').replace(/ /g, '');
    }

    /**
     * 去掉字符串中的空格、\0
     * @param target 
     * @param sourceData 源数据
     * @returns 处理后数据
     */
    static DelspacePage(target: IPage, sourceData: string): string {
        return ScriptFunction.Delspace(sourceData);
    }

    /**
     * 计算分隔符分开的字段的个数
     * @param sourceData 源数据
     * @param separator 分隔字符
     * @returns 字段个数
     */
    static StrFldCnt(sourceData: string, separator: string): number {
        return sourceData.split(separator).length;
    }

    /**
     * 计算分隔符分开的字段的个数
     * @param target 
     * @param sourceData 源数据
     * @param separator 分隔字符
     * @returns 字段个数
     */
    static StrFldCntPage(target: IPage, sourceData: string, separator: string): number {
        return ScriptFunction.StrFldCnt(sourceData, separator);
    }

    /**
     * 按索引取由分隔符分开的某个字段
     * @param sourceData 源数据
     * @param separator 分隔符
     * @param index 索引值
     * @returns 字段值
     */
    static StrFld(sourceData: string, separator: string, index: number): string {
        const array = sourceData.split(separator);
        return array[index];
    }

    /**
     * 按索引取由分隔符分开的某个字段
     * @param target 
     * @param sourceData 源数据
     * @param separator 分隔符
     * @param index 索引值
     * @returns 字段值
     */
    static StrFldPage(target: IPage, sourceData: string, separator: string, index: number): string {
        return ScriptFunction.StrFld(sourceData, separator, index);
    }

    /**
     * 计算两个日期之间的绝对差值（天数）
     * @param fDate 起始日期
     * @param sDate 终止日期
     * @returns 相距天数
     */
    static Func(fDate: string, sDate: string): number {
        const startDate = new Date(parseInt(fDate.substring(0, 4)), parseInt(fDate.substring(4, 2)) - 1, parseInt(fDate.substring(6)));
        const endDate = new Date(parseInt(sDate.substring(0, 4)), parseInt(sDate.substring(4, 2)) - 1, parseInt(sDate.substring(6)));
        const timeSpan = endDate.getTime() - startDate.getTime();
        return Math.floor(timeSpan / (1000 * 60 * 60 * 24));
    }

    /**
     * 计算两个日期之间的绝对差值(天数)
     * @param target 
     * @param fDate 起始日期
     * @param sDate 终止日期
     * @returns 相距天数
     */
    static FuncPage(target: IPage, fDate: string, sDate: string): number {
        return ScriptFunction.Func(fDate, sDate);
    }

    /**
     * 将数字类型转换成大写金额字符串
     * @param num 数字
     * @returns 大写金额字符串
     */
    static ChangeToCNY(num: number): string {
        const str1 = "零壹贰叁肆伍陆柒捌玖";
        const str2 = "万仟佰拾亿仟佰拾万仟佰拾元角分";
        let str3 = "";
        let str4 = "";
        let str5 = "";
        let i = 0;
        let j = 0;
        let ch1 = "";
        let ch2 = "";
        let nzero = 0;
        let temp = 0;

        num = Math.round(Math.abs(num) * 100) / 100;
        str4 = (Math.floor(num * 100)).toString();
        j = str4.length;
        if (j > 15) {
            return '';
        }

        const str2Sub = str2.substring(15 - j);

        for (i = 0; i < j; i++) {
            str3 = str4.substring(i, i + 1);
            temp = parseInt(str3, 10);
            if (i !== (j - 3) && i !== (j - 7) && i !== (j - 11) && i !== (j - 15)) {
                if (str3 === "0") {
                    ch1 = "";
                    ch2 = "";
                    nzero = nzero + 1;
                } else {
                    if (str3 !== "0" && nzero !== 0) {
                        ch1 = "零" + str1[temp];
                        ch2 = str2Sub[i];
                        nzero = 0;
                    } else {
                        ch1 = str1[temp];
                        ch2 = str2Sub[i];
                        nzero = 0;
                    }
                }
            } else {
                if (str3 !== "0" && nzero !== 0) {
                    ch1 = "零" + str1[temp];
                    ch2 = str2Sub[i];
                    nzero = 0;
                } else {
                    if (str3 !== "0" && nzero === 0) {
                        ch1 = str1[temp];
                        ch2 = str2Sub[i];
                        nzero = 0;
                    } else {
                        if (str3 === "0" && nzero >= 3) {
                            ch1 = "";
                            ch2 = "";
                            nzero = nzero + 1;
                        } else {
                            if (j >= 11) {
                                ch1 = "";
                                nzero = nzero + 1;
                            } else {
                                ch1 = "";
                                ch2 = str2Sub[i];
                                nzero = nzero + 1;
                            }
                        }
                    }
                }
            }

            if (i === (j - 11) || i === (j - 3) || (i === (i - 7) && nzero <= 3)) {
                nzero = 0;
                ch2 = str2Sub[i];
            }
            str5 = str5 + ch1 + ch2;

            if (i === j - 1 && str3 === "0") {
                str5 = str5 + '整';
            }
        }
        if (num === 0) {
            str5 = "零元整";
        }
        return str5;
    }

    /**
     * 将数字类型转换成大写金额字符串
     * @param target 
     * @param num 数字
     * @returns 大写金额字符串
     */
    static ChangeToCNYPage(target: IPage, num: number): string {
        return ScriptFunction.ChangeToCNY(num);
    }

    /**
     * 按格式解析返回字串，给combox添加项
     * @param comboBox combox对象
     * @param fileData 源数据
     * @param formatString 赋值格式
     * @returns 是否成功
     */
    static SetSel(comboBox: ComboBox, fileData: string, formatString: string): boolean {
        if (comboBox === null || fileData === '' || formatString === '') {
            return false;
        }

        const lengths = formatString.toLowerCase().split(/[otv]/);
        let cellLength = 0;
        let titleIndex = 0;
        let titleLength = 0;
        let valueIndex = 0;
        let valueLength = 0;
        let counter = 0;

        for (let i = 1; i < lengths.length; i++) {
            const length = parseInt(lengths[i], 10);
            switch (formatString[counter]) {
                case 't':
                    titleIndex = cellLength;
                    titleLength = length;
                    break;
                case 'v':
                    valueIndex = cellLength;
                    valueLength = length;
                    break;
                case 'o':
                    break;
                default:
                    TradeLogger.Error(
                        `SetSel函数执行出错！formatString参数[${formatString}]格式解析异常！`
                    );
                    return false;
            }
            counter++;
            counter += lengths[i].length;
            cellLength += length;
        }

        const data = new TextEncoder().encode(fileData);
        const count = Math.floor(data.length / cellLength);
        let titleMaxLength = 0;
        const dict: { [key: string]: string } = {};

        for (let i = 0; i < count; i++) {
            const btempTitle = data.slice(titleIndex + i * cellLength, titleIndex + i * cellLength + titleLength);
            const title = new TextDecoder(CommonParames.Coding).decode(btempTitle).trim();

            const btempValue = data.slice(valueIndex + i * cellLength, valueIndex + i * cellLength + valueLength);
            const varValue = new TextDecoder(CommonParames.Coding).decode(btempValue);

            dict[title] = varValue;

            if (title.length > titleMaxLength) {
                titleMaxLength = title.length;
            }
        }

        comboBox.SetItems(dict);
        comboBox.MinWidth = titleMaxLength * comboBox.FontSize;
        return true;
    }

    /**
     * 按格式解析返回字串，给combox添加项
     * @param target 
     * @param comboBox combox对象
     * @param fileData 源数据
     * @param formatString 赋值格式
     * @returns 是否成功
     */
    static SetSelPage(target: IPage, comboBox: ComboBox, fileData: string, formatString: string): boolean {
        return ScriptFunction.SetSel(comboBox, fileData, formatString);
    }

    /**
     * 格式化Title字符串
     * @param title 待格式化的Title字符串
     * @returns 格式化后的Title字符串
     */
    static FormatTitle(title: string): string {
        let i = 0;
        for (i = 0; i < title.length; i++) {
            if (title[i] === '.') {
                i++;
                break;
            }
            if (ScriptFunction.IsChinese(title[i])) {
                break;
            }
        }
        if (i < title.length) {
            title = title.substring(i);
        }
        return ScriptFunction.Delspace(title);
    }

    /**
     * 判断是否为中文字符
     * @param c 待判断的字符
     * @returns 是否为中文字符
     */
    static IsChinese(c: string): boolean {
        const code = c.charCodeAt(0);
        return code >= 0x4E00 && code <= 0x9FA5;
    }

    // 控制相关

    /**
     * 返回错误编号对应的错误信息
     * @param errorNo 错误信息编号
     * @returns 错误信息
     */
    static GetError(errorNo: string): string {
        // TODO:调用web服务初始化信息
        // InitializeHandle.InitErrorMap();
        const errorMessage = CommonParames.MsgErrorMap[errorNo] || "未知的错误代码";
        return `[${errorNo}]${errorMessage}`;
    }

    /**
     * 返回错误编号对应的错误信息
     * @param target 
     * @param errorNo 错误信息编号
     * @returns 错误信息
     */
    static GetErrorPage(target: IPage, errorNo: string): string {
        return ScriptFunction.GetError(errorNo);
    }

    /**
     * 返回错误编号对应的错误信息
     * @param target 
     * @param errorNo 错误信息编号
     * @param errorExt 额外的错误信息
     * @returns 错误信息
     */
    static GetErrorPageWithExt(target: IPage, errorNo: string, errorExt: string): string {
        if (errorExt === '') {
            return ScriptFunction.GetError(errorNo);
        } else {
            return `${ScriptFunction.GetError(errorNo)},${errorExt}!`;
        }
    }

    /**
     * 取得当前机器的IPv4地址
     * @returns IP地址
     */
    static async GetIPv4Addresses(): Promise<string[]> {
        try {
            const response = await fetch('https://api.ipify.org?format=json');
            const data = await response.json();
            return [data.ip];
        } catch (error) {
            TradeLogger.Error(error);
            return [];
        }
    }

    /**
     * 取得当前机器的IPv4地址
     * @param target 
     * @returns IPv4字符串组
     */
    static async GetIPv4AddressesPage(target: IPage): Promise<string[]> {
        return ScriptFunction.GetIPv4Addresses();
    }

    // 文件操作相关

    /**
     * 获取服务端文件
     * @param fileName 文件名
     * @returns 文件内容
     */
    static async Getfiletxt(fileName: string): Promise<string> {
        const fileData = FilesHandle.GetFileData(fileName);
        return new TextDecoder(CommonParames.Coding).decode(fileData);
    }

    /**
     * 获取服务端文件
     * @param target 
     * @param fileName 文件名
     * @returns 文件内容
     */
    static async GetfiletxtPage(target: IPage, fileName: string): Promise<string> {
        return ScriptFunction.Getfiletxt(fileName);
    }

    /**
     * 往服务端保存文件
     * @param fileName 文件名
     * @param fileContent 文件内容
     * @param append 是否append追加方式
     * @returns 是否保存成功
     */
    static async Savefiletxt(fileName: string, fileContent: string, append: boolean): Promise<boolean> {
        const fileData = new TextEncoder().encode(fileContent);
        return FilesHandle.SaveFileData(fileName, fileData, append);
    }

    /**
     * 往服务端保存文件
     * @param target 
     * @param fileName 文件名
     * @param fileContent 文件内容
     * @param append 是否append追加方式
     * @returns 是否保存成功
     */
    static async SavefiletxtPage(target: IPage, fileName: string, fileContent: string, append: boolean): Promise<boolean> {
        return ScriptFunction.Savefiletxt(fileName, fileContent, append);
    }
}

export default ScriptFunction;