import { EncrypDecryptHelper } from '../../../common/BasicFunctions/BaseClasses/EncrypDecryptHelper'

// 假设 TransitEntity 和 AttachFile 类型定义如下
interface TransitEntity {
    ServiceName: string;
    FuncName: string;
    Parameters: { [key: string]: string };
    AttachFiles: AttachFile[];
}

interface AttachFile {
    AttachType: string;
    AttachValue: any;
    AttachIndex: string;
}

// 假设 PlatformSettings 和 PlatformLogger 定义如下
const PlatformSettings = {
    Encoding: {
        BodyName: 'utf-8',
        GetBytes: (str: string) => new TextEncoder().encode(str),
        GetString: (bytes: Uint8Array) => new TextDecoder().decode(bytes)
    },
    IsEncrypt: true
};

const PlatformLogger = {
    SystemInfo: (info: string) => console.log(info)
};

// 假设 Types 定义如下
const Types = {
    BaseType: '1',
    ByteType: '2',
    TableType: '3'
};

// 假设 LoginUserInfo 定义如下
const LoginUserInfo = {
    TellerNo: '123456'
};

// 假设 EncrypDecryptHelper 定义如下
// const EncrypDecryptHelper = {
//     Encrypt: (data: Uint8Array, flag: boolean) => data, // 简单示例，实际需要实现加密逻辑
//     Decrypt: (data: Uint8Array, flag: boolean) => data  // 简单示例，实际需要实现解密逻辑
// };

class MessageHandle {
    static GroupMessage(transitentity: TransitEntity): Uint8Array {
        const ms = new Uint8Array(0);
        const logInfo = new StringBuilder();
        const xmlMark = `<?xml version="1.0" encoding="${PlatformSettings.Encoding.BodyName}"?>`;
        let header = '';
        let data = '';
        const doc = new DOMParser().parseFromString('<root></root>', 'text/xml');

        logInfo.appendLine();
        logInfo.appendLine('组包开始:');

        // 数据域
        const content = doc.createElement('Content');
        const servicename = doc.createElement('ServiceName');
        servicename.textContent = transitentity.ServiceName;
        const methodname = doc.createElement('MethodName');
        methodname.textContent = transitentity.FuncName;
        const parameters = doc.createElement('Parameters');
        logInfo.appendLine(`服务方法：${transitentity.ServiceName}:${transitentity.FuncName}`);

        for (const [key, value] of Object.entries(transitentity.Parameters)) {
            const parameter = doc.createElement('Parameter');
            parameter.setAttribute('Index', key);
            parameter.setAttribute('Value', value);
            parameters.appendChild(parameter);
            logInfo.appendLine(`参数：第${key}位参数:${value}`);
        }

        content.appendChild(servicename);
        content.appendChild(methodname);
        content.appendChild(parameters);
        doc.documentElement.appendChild(content);
        data = xmlMark + new XMLSerializer().serializeToString(doc.documentElement);
        const dataByte = PlatformSettings.Encoding.GetBytes(data);

        // 附件
        let fileByte = new Uint8Array(0);
        if (transitentity.AttachFiles.length > 0) {
            const fileMs = new Uint8Array(0);
            let index = 0;
            for (const item of transitentity.AttachFiles) {
                let fileValue = '';
                let fByte: Uint8Array;
                let fileType: Uint8Array;

                if (item.AttachType === Types.BaseType) {
                    fileType = PlatformSettings.Encoding.GetBytes(Types.BaseType);
                    fByte = PlatformSettings.Encoding.GetBytes(item.AttachValue.toString());
                } else if (item.AttachType === Types.ByteType) {
                    fileType = PlatformSettings.Encoding.GetBytes(Types.ByteType);
                    fByte = item.AttachValue as Uint8Array;
                } else if (item.AttachType === Types.TableType) {
                    fileType = PlatformSettings.Encoding.GetBytes(Types.TableType);
                    const tableDoc = new DOMParser().parseFromString('<Table></Table>', 'text/xml');
                    const fileTable = item.AttachValue; // 假设是一个合适的表格数据结构
                    if (fileTable) {
                        const table = tableDoc.documentElement;
                        const rowNumber = tableDoc.createElement('RowNumber');
                        const columnNumber = tableDoc.createElement('ColumnNumber');
                        rowNumber.textContent = fileTable.length.toString();
                        columnNumber.textContent = fileTable[0]?.length.toString() || '0';
                        table.appendChild(rowNumber);
                        table.appendChild(columnNumber);

                        if (fileTable[0]?.length > 0) {
                            const columns = tableDoc.createElement('Columns');
                            table.appendChild(columns);
                            const fields = tableDoc.createElement('Fields');
                            columns.appendChild(fields);
                            for (const column of fileTable[0]) {
                                const field = tableDoc.createElement('Field');
                                field.textContent = column;
                                fields.appendChild(field);
                            }
                        }

                        if (fileTable.length > 0) {
                            const rows = tableDoc.createElement('Rows');
                            table.appendChild(rows);
                            for (const list of fileTable) {
                                const row = tableDoc.createElement('row');
                                rows.appendChild(row);
                                const fields = tableDoc.createElement('Fields');
                                row.appendChild(fields);
                                for (const fileCell of list) {
                                    const field = tableDoc.createElement('Field');
                                    field.textContent = fileCell.toString();
                                    fields.appendChild(field);
                                }
                            }
                        }
                    }
                    fileValue = xmlMark + new XMLSerializer().serializeToString(tableDoc.documentElement);
                    fByte = PlatformSettings.Encoding.GetBytes(fileValue);
                }

                const flen = PlatformSettings.Encoding.GetBytes(fByte.length.toString().padStart(8, '0'));
                const findex = PlatformSettings.Encoding.GetBytes(item.AttachIndex.padStart(2, '0'));
                const fbak = PlatformSettings.Encoding.GetBytes(''.padStart(19, '0'));

                // 模拟写入操作
                fileByte = new Uint8Array([...fileByte, ...flen, ...fileType, ...findex, ...fbak, ...fByte]);

                logInfo.appendLine(`第${++index}附件为：${fileValue}`);
            }
        }

        // 报文头
        const dataLen = dataByte.length.toString().padStart(6, '0');
        const sendType = '0';
        const branchNo = '000000';
        const terminalNo = '000000000000';
        const sendChannel = '0';
        const encryptType = '0';
        const fileCnt = transitentity.AttachFiles.length.toString();
        const terllerNo = LoginUserInfo.TellerNo.padStart(10, ' ');
        const bak = ''.padStart(26, '0');

        header = dataLen + sendType + branchNo + terminalNo + sendChannel + encryptType + fileCnt + terllerNo + bak;
        logInfo.appendLine(`64位报文头:${header}`);
        const headerByte = PlatformSettings.Encoding.GetBytes(header);

        // 报文加密与长度计算
        let msgByte = new Uint8Array([...headerByte, ...dataByte, ...fileByte]);
        if (PlatformSettings.IsEncrypt) {
            msgByte = EncrypDecryptHelper.Encrypt(msgByte, true);
        }
        const xmlLenByte = PlatformSettings.Encoding.GetBytes(msgByte.length.toString().padStart(8, '0'));
        const resultByte = new Uint8Array([...xmlLenByte, ...msgByte]);

        logInfo.appendLine('组包结束');
        PlatformLogger.SystemInfo(logInfo.toString());
        return resultByte;
    }

    static AnalyseMessage(msg: Uint8Array): AttachFile[] | null {
        let attachfiles: AttachFile[] | null = null;
        const ms = msg;
        const logInfo = new StringBuilder();

        if (msg.length === 0) {
            logInfo.appendLine('解包数据异常');
            PlatformLogger.SystemInfo(logInfo.toString());
            return null;
        }

        const doc = new DOMParser().parseFromString('<root></root>', 'text/xml');
        logInfo.appendLine();
        logInfo.appendLine('解包开始');

        // 报文头 验证总长度
        const lenthByte = ms.slice(0, 8);
        const xmlLen = parseInt(PlatformSettings.Encoding.GetString(lenthByte), 10);
        if (xmlLen !== ms.length - 8) {
            logInfo.appendLine('报文总长度验证失败');
            PlatformLogger.SystemInfo(logInfo.toString());
            return null;
        }

        let message = ms.slice(8);
        let finalmessage = message;
        if (PlatformSettings.IsEncrypt) {
            finalmessage = EncrypDecryptHelper.Decrypt(message, true);
        }

        const headerByte = finalmessage.slice(0, 64);
        const header = PlatformSettings.Encoding.GetString(headerByte);
        logInfo.appendLine(`64位报文头：${header}`);

        const dataLen = parseInt(header.substring(0, 6), 10);
        const FileCnt = parseInt(header.substring(27, 28), 10);

        // 附件
        if (FileCnt > 0) {
            attachfiles = [];
            let fileByte = finalmessage.slice(64 + dataLen);
            let fl = 0;
            for (let i = 0; i < FileCnt; i++) {
                const attachfile: AttachFile = {
                    AttachType: '',
                    AttachValue: null,
                    AttachIndex: ''
                };
                const fhead = PlatformSettings.Encoding.GetString(fileByte.slice(0, 30));
                const flen = parseInt(fhead.substring(0, 8), 10);
                const fileValue = fileByte.slice(30, 30 + flen);

                if (fhead.substring(8, 9) === Types.BaseType) {
                    attachfile.AttachType = Types.BaseType;
                    attachfile.AttachValue = PlatformSettings.Encoding.GetString(fileValue);
                } else if (fhead.substring(8, 9) === Types.ByteType) {
                    attachfile.AttachType = Types.ByteType;
                    attachfile.AttachValue = fileValue;
                } else if (fhead.substring(8, 9) === Types.TableType) {
                    attachfile.AttachType = Types.TableType;
                    const fileDt = PlatformSettings.Encoding.GetString(fileValue);
                    const tableDoc = new DOMParser().parseFromString(fileDt, 'text/xml');
                    logInfo.appendLine(`DataTable附件${i + 1}：${fileDt}`);

                    const table = tableDoc.querySelector('Table');
                    if (table) {
                        const dataTable = [];
                        const columns = table.querySelector('Columns');
                        if (columns) {
                            const fields = columns.querySelectorAll('Field');
                            const columnNames = Array.from(fields).map(field => field.textContent);
                            dataTable.push(columnNames);
                        }
                        const rows = table.querySelector('Rows');
                        if (rows) {
                            const rowElements = rows.querySelectorAll('row');
                            // for (const rowElement of rowElements) {
                            //     const fields = rowElement.querySelectorAll('Field');
                            //     const rowData = Array.from(fields).map(field => field.textContent);
                            //     dataTable.push(rowData);
                            // }
                            //TODO报错了待解决
                        }
                        attachfile.AttachValue = dataTable;
                    }
                }

                fl += flen + 30;
                fileByte = finalmessage.slice(64 + dataLen + fl);
                attachfiles.push(attachfile);
            }
        }

        logInfo.appendLine('解包结束');
        PlatformLogger.SystemInfo(logInfo.toString());
        return attachfiles;
    }
}

// 简单的 StringBuilder 实现
class StringBuilder {
    private value = '';

    appendLine(line = '') {
        this.value += line + '\n';
    }

    toString() {
        return this.value;
    }
}

export default MessageHandle;
