package backup_export_cdr

import (
	"encoding/json"
	"fmt"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"time"

	"be.ems/src/framework/cron"
	"be.ems/src/framework/i18n"
	"be.ems/src/framework/logger"
	"be.ems/src/framework/utils/date"
	"be.ems/src/framework/utils/file"
	"be.ems/src/framework/utils/parse"
	neModel "be.ems/src/modules/ne/model"
	neService "be.ems/src/modules/ne/service"
	neDataService "be.ems/src/modules/ne_data/service"
	systemService "be.ems/src/modules/system/service"
)

var NewProcessor = &BackupExportCDRProcessor{
	count:           0,
	backupService:   neDataService.NewBackup,
	sysDictService:  systemService.NewSysDictData,
	neInfoService:   neService.NewNeInfo,
	cdrEventService: neDataService.NewCDREvent,
}

// BackupExportCDR 队列任务处理
type BackupExportCDRProcessor struct {
	count           int                        // 执行次数
	backupService   *neDataService.Backup      // 备份相关服务
	sysDictService  *systemService.SysDictData // 字典类型数据服务
	neInfoService   *neService.NeInfo          // 网元信息服务
	cdrEventService *neDataService.CDREvent    // CDR会话事件服务
}

func (s *BackupExportCDRProcessor) Execute(data any) (any, error) {
	s.count++ // 执行次数加一
	options := data.(cron.JobData)
	sysJob := options.SysJob
	logger.Infof("重复:%v 任务ID:%d  执行次数:%d", options.Repeat, sysJob.JobId, s.count)
	// 返回结果，用于记录执行结果
	result := map[string]any{
		"count": s.count,
	}

	var params struct {
		DataType []string `json:"dataType"` // 类型支持 ims/smsc/smf/sgwc
		FileType string   `json:"fileType"` // 文件类型 csv/xlsx
		Hour     int      `json:"hour"`     // 数据时间从任务执行时间前的小时数
	}
	if err := json.Unmarshal([]byte(sysJob.TargetParams), &params); err != nil {
		return nil, err
	}
	if !(params.FileType == "csv" || params.FileType == "xlsx") {
		return nil, fmt.Errorf("file type error, only support csv,xlsx")
	}

	for _, v := range params.DataType {
		// 前 hour 小时
		now := time.Now()
		end := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
		start := end.Add(-time.Duration(params.Hour) * time.Hour)
		query := map[string]string{
			"neType":    "",
			"neId":      "",
			"rmUID":     "",
			"beginTime": fmt.Sprint(start.UnixMilli()),
			"endTime":   fmt.Sprint(end.UnixMilli()),
		}
		switch v {
		case "ims":
			neList := s.neInfoService.Find(neModel.NeInfo{NeType: "IMS"}, false, false)
			for _, ne := range neList {
				query["neType"] = "IMS"
				query["neId"] = ne.NeId
				query["rmUID"] = ne.RmUID
				result[ne.NeName] = s.exportIMS(query, params.FileType)
			}
		case "smsc":
			neList := s.neInfoService.Find(neModel.NeInfo{NeType: "SMSC"}, false, false)
			for _, ne := range neList {
				query["neType"] = "SMSC"
				query["neId"] = ne.NeId
				query["rmUID"] = ne.RmUID
				result[ne.NeName] = s.exportSMSC(query, params.FileType)
			}
		case "smf":
			neList := s.neInfoService.Find(neModel.NeInfo{NeType: "SMF"}, false, false)
			for _, ne := range neList {
				query["neType"] = "SMF"
				query["neId"] = ne.NeId
				query["rmUID"] = ne.RmUID
				result[ne.NeName] = s.exportSMF(query, params.FileType)
			}
		case "sgwc":
			neList := s.neInfoService.Find(neModel.NeInfo{NeType: "SGWC"}, false, false)
			for _, ne := range neList {
				query["neType"] = "SGWC"
				query["neId"] = ne.NeId
				query["rmUID"] = ne.RmUID
				result[ne.NeName] = s.exportSGWC(query, params.FileType)
			}
		}
	}

	// 返回结果，用于记录执行结果
	return result, nil
}

// exportIMS 导出IMS-CDR会话事件数据
func (s BackupExportCDRProcessor) exportIMS(query map[string]string, fileType string) string {
	language := "en"
	neType := query["neType"]
	neTypeLower := strings.ToLower(neType)
	neId := query["neId"]
	endTime := parse.Number(query["endTime"])
	rows, total := s.cdrEventService.FindByPage(neType, query)
	if total == 0 {
		return "no data"
	}

	// 导出文件名称
	dateStr := date.ParseDateToStr(endTime, date.YYYYMMDDHHMMSS)
	fileName := fmt.Sprintf("%s_%s_cdr_export_%d_%s.%s", neTypeLower, neId, len(rows), dateStr, fileType)
	filePath := filepath.Join(s.backupService.BACKUP_DIR, fmt.Sprintf("/cdr/%s", neTypeLower), fileName)
	if runtime.GOOS == "windows" {
		filePath = fmt.Sprintf("C:%s", filePath)
	}

	if fileType == "csv" {
		// 转换数据
		data := [][]string{
			{
				"ID",
				"NE Name",
				"Record Behavior",
				"Type",
				"Caller",
				"Called",
				"Duration",
				"Result Code",
				"Result Cause",
				"Call Start Time",
				"Hangup Time",
			},
		}
		// 读取字典数据 CDR SIP响应代码类别类型
		dictCDRSipCode := s.sysDictService.FindByType("cdr_sip_code")
		// 读取字典数据 CDR SIP响应代码类别类型原因
		dictCDRSipCodeCause := s.sysDictService.FindByType("cdr_sip_code_cause")
		// 读取字典数据 CDR 呼叫类型
		dictCDRCallType := s.sysDictService.FindByType("cdr_call_type")
		for _, row := range rows {
			// 解析 JSON 字符串为 map
			var cdrJSON map[string]any
			err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON)
			if err != nil {
				logger.Warnf("CDRExport Error parsing JSON: %s", err.Error())
				continue
			}
			// 记录类型
			recordType := ""
			if v, ok := cdrJSON["recordType"]; ok && v != nil {
				recordType = v.(string)
			}
			// 呼叫类型
			callType := "sms"
			callTypeLable := "SMS"
			if v, ok := cdrJSON["callType"]; ok && v != nil {
				callType = v.(string)
				for _, v := range dictCDRCallType {
					if callType == v.DataValue {
						callTypeLable = i18n.TKey(language, v.DataLabel)
						break
					}
				}
			}
			// 被叫
			called := ""
			if v, ok := cdrJSON["calledParty"]; ok && v != nil {
				called = v.(string)
			}
			// 主叫
			caller := ""
			if v, ok := cdrJSON["callerParty"]; ok && v != nil {
				caller = v.(string)
			}
			// 时长
			duration := "-"
			if v, ok := cdrJSON["callDuration"]; ok && v != nil && callType != "sms" {
				duration = fmt.Sprintf("%ds", parse.Number(v))
			}
			// 呼叫结果 非短信都有code作为结果 sms短信都ok
			callResult := "Other"
			callCause := "Call failure for other reason"
			if callType == "sms" {
				callResult = "Success"
				callCause = "Normal Send"
			} else {
				if v, ok := cdrJSON["cause"]; ok && v != nil {
					cause := fmt.Sprint(v)
					for _, v := range dictCDRSipCode {
						if cause == v.DataValue {
							callResult = i18n.TKey(language, v.DataLabel)
							break
						}
					}
					for _, v := range dictCDRSipCodeCause {
						if cause == v.DataValue {
							callCause = i18n.TKey(language, v.DataLabel)
							break
						}
					}
				}
			}
			// 呼叫时间
			seizureTimeStr := ""
			if v, ok := cdrJSON["seizureTime"]; ok && v != nil {
				if seizureTime := parse.Number(v); seizureTime > 0 {
					seizureTimeStr = date.ParseDateToStr(seizureTime, date.YYYY_MM_DDTHH_MM_SSZ)
				} else {
					seizureTimeStr = v.(string)
				}
			}
			// 挂断时间
			releaseTimeStr := ""
			if v, ok := cdrJSON["releaseTime"]; ok && v != nil {
				if releaseTime := parse.Number(v); releaseTime > 0 {
					releaseTimeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ)
				} else {
					releaseTimeStr = v.(string)
				}
			}

			data = append(data, []string{
				fmt.Sprint(row.ID),
				row.NeName,
				recordType,
				callTypeLable,
				caller,
				called,
				duration,
				callResult,
				callCause,
				seizureTimeStr,
				releaseTimeStr,
			})
		}
		// 输出到文件
		if err := file.WriterFileCSV(data, filePath); err != nil {
			logger.Errorf("export operate log err => %v", err.Error())
			return "export err"
		}
	}

	if fileType == "xlsx" {
		// 第一行表头标题
		headerCells := map[string]string{
			"A1": "ID",
			"B1": "NE Name",
			"C1": "Record Behavior",
			"D1": "Type",
			"E1": "Caller",
			"F1": "Called",
			"G1": "Duration",
			"H1": "Result Code",
			"I1": "Result Cause",
			"J1": "Call Start Time",
			"K1": "Hangup Time",
		}
		// 读取字典数据 CDR SIP响应代码类别类型
		dictCDRSipCode := s.sysDictService.FindByType("cdr_sip_code")
		// 读取字典数据 CDR SIP响应代码类别类型原因
		dictCDRSipCodeCause := s.sysDictService.FindByType("cdr_sip_code_cause")
		// 读取字典数据 CDR 呼叫类型
		dictCDRCallType := s.sysDictService.FindByType("cdr_call_type")
		// 从第二行开始的数据
		dataCells := make([]map[string]any, 0)
		for i, row := range rows {
			idx := strconv.Itoa(i + 2)
			// 解析 JSON 字符串为 map
			var cdrJSON map[string]any
			err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON)
			if err != nil {
				logger.Warnf("CDRExport Error parsing JSON: %s", err.Error())
				continue
			}
			// 记录类型
			recordType := ""
			if v, ok := cdrJSON["recordType"]; ok && v != nil {
				recordType = v.(string)
			}
			// 呼叫类型
			callType := "sms"
			callTypeLable := "SMS"
			if v, ok := cdrJSON["callType"]; ok && v != nil {
				callType = v.(string)
				for _, v := range dictCDRCallType {
					if callType == v.DataValue {
						callTypeLable = i18n.TKey(language, v.DataLabel)
						break
					}
				}
			}
			// 被叫
			called := ""
			if v, ok := cdrJSON["calledParty"]; ok && v != nil {
				called = v.(string)
			}
			// 主叫
			caller := ""
			if v, ok := cdrJSON["callerParty"]; ok && v != nil {
				caller = v.(string)
			}
			// 时长
			duration := "-"
			if v, ok := cdrJSON["callDuration"]; ok && v != nil && callType != "sms" {
				duration = fmt.Sprintf("%ds", parse.Number(v))
			}
			// 呼叫结果 非短信都有code作为结果 sms短信都ok
			callResult := "Other"
			callCause := "Call failure for other reason"
			if callType == "sms" {
				callResult = "Success"
				callCause = "Normal Send"
			} else {
				if v, ok := cdrJSON["cause"]; ok && v != nil {
					cause := fmt.Sprint(v)
					for _, v := range dictCDRSipCode {
						if cause == v.DataValue {
							callResult = i18n.TKey(language, v.DataLabel)
							break
						}
					}
					for _, v := range dictCDRSipCodeCause {
						if cause == v.DataValue {
							callCause = i18n.TKey(language, v.DataLabel)
							break
						}
					}
				}
			}
			// 呼叫时间
			seizureTimeStr := ""
			if v, ok := cdrJSON["seizureTime"]; ok && v != nil {
				if seizureTime := parse.Number(v); seizureTime > 0 {
					seizureTimeStr = date.ParseDateToStr(seizureTime, date.YYYY_MM_DDTHH_MM_SSZ)
				} else {
					seizureTimeStr = v.(string)
				}
			}
			// 挂断时间
			releaseTimeStr := ""
			if v, ok := cdrJSON["releaseTime"]; ok && v != nil {
				if releaseTime := parse.Number(v); releaseTime > 0 {
					releaseTimeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ)
				} else {
					releaseTimeStr = v.(string)
				}
			}

			dataCells = append(dataCells, map[string]any{
				"A" + idx: row.ID,
				"B" + idx: row.NeName,
				"C" + idx: recordType,
				"D" + idx: callTypeLable,
				"E" + idx: caller,
				"F" + idx: called,
				"G" + idx: duration,
				"H" + idx: callResult,
				"I" + idx: callCause,
				"J" + idx: seizureTimeStr,
				"K" + idx: releaseTimeStr,
			})
		}
		// 导出数据表格
		if err := file.WriterFileExecl(headerCells, dataCells, filePath, ""); err != nil {
			logger.Errorf("export operate log err => %v", err.Error())
			return "export err"
		}
	}

	// 上传到FTP服务器
	if err := s.backupService.FTPPushFile(filePath, "cdr"); err != nil {
		return "ok, ftp err:" + err.Error()
	}
	return "ok"
}

// exportSMSC 导出SMSC-CDR会话事件数据
func (s BackupExportCDRProcessor) exportSMSC(query map[string]string, fileType string) string {
	language := "en"
	neType := query["neType"]
	neTypeLower := strings.ToLower(neType)
	neId := query["neId"]
	endTime := parse.Number(query["endTime"])
	rows, total := s.cdrEventService.FindByPage(neType, query)
	if total == 0 {
		return "no data"
	}

	// 导出文件名称
	dateStr := date.ParseDateToStr(endTime, date.YYYYMMDDHHMMSS)
	fileName := fmt.Sprintf("%s_%s_cdr_export_%d_%s.%s", neTypeLower, neId, len(rows), dateStr, fileType)
	filePath := filepath.Join(s.backupService.BACKUP_DIR, fmt.Sprintf("/cdr/%s", neTypeLower), fileName)
	if runtime.GOOS == "windows" {
		filePath = fmt.Sprintf("C:%s", filePath)
	}

	if fileType == "csv" {
		// 转换数据
		data := [][]string{
			{
				"ID",
				"NE Name",
				"Record Behavior",
				"Service Type",
				"Caller",
				"Called",
				"Result Code",
				"Result Cause",
				"Time",
			},
		}
		// 读取字典数据 CDR 原因码
		dictCDRSMSCCauseCode := s.sysDictService.FindByType("cdr_cause_smsc")
		for _, row := range rows {
			// 解析 JSON 字符串为 map
			var cdrJSON map[string]interface{}
			err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON)
			if err != nil {
				logger.Warnf("CDRExport Error parsing JSON: %s", err.Error())
				continue
			}
			// 记录类型
			recordType := ""
			if v, ok := cdrJSON["recordType"]; ok && v != nil {
				recordType = v.(string)
			}
			// 服务类型
			serviceType := ""
			if v, ok := cdrJSON["serviceType"]; ok && v != nil {
				serviceType = v.(string)
			}
			// 被叫
			called := ""
			if v, ok := cdrJSON["calledParty"]; ok && v != nil {
				called = v.(string)
			}
			// 主叫
			caller := ""
			if v, ok := cdrJSON["callerParty"]; ok && v != nil {
				caller = v.(string)
			}
			// 呼叫结果 0失败，1成功
			callResult := "FAILED"
			if v, ok := cdrJSON["result"]; ok && v != nil {
				resultVal := parse.Number(v)
				if resultVal == 1 {
					callResult = "SUCCESS"
				}
			}
			// 结果原因
			callCause := "UNKNOW ERROR"
			if v, ok := cdrJSON["cause"]; ok && v != nil {
				cause := fmt.Sprint(v)
				for _, v := range dictCDRSMSCCauseCode {
					if cause == v.DataValue {
						callCause = i18n.TKey(language, v.DataLabel)
						break
					}
				}
			}
			// 取时间
			timeStr := ""
			if v, ok := cdrJSON["updateTime"]; ok && v != nil {
				if releaseTime := parse.Number(v); releaseTime > 0 {
					timeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ)
				} else {
					timeStr = v.(string)
				}
			}

			data = append(data, []string{
				fmt.Sprint(row.ID),
				row.NeName,
				recordType,
				serviceType,
				caller,
				called,
				callResult,
				callCause,
				timeStr,
			})
		}
		// 输出到文件
		if err := file.WriterFileCSV(data, filePath); err != nil {
			logger.Errorf("export operate log err => %v", err.Error())
			return "export err"
		}
	}

	if fileType == "xlsx" {
		// 第一行表头标题
		headerCells := map[string]string{
			"A1": "ID",
			"B1": "NE Name",
			"C1": "Record Behavior",
			"D1": "Service Type",
			"E1": "Caller",
			"F1": "Called",
			"G1": "Result Code",
			"H1": "Result Cause",
			"I1": "Time",
		}
		// 读取字典数据 CDR 原因码
		dictCDRSMSCCauseCode := s.sysDictService.FindByType("cdr_cause_smsc")
		// 从第二行开始的数据
		dataCells := make([]map[string]any, 0)
		for i, row := range rows {
			idx := strconv.Itoa(i + 2)
			// 解析 JSON 字符串为 map
			var cdrJSON map[string]interface{}
			err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON)
			if err != nil {
				logger.Warnf("CDRExport Error parsing JSON: %s", err.Error())
				continue
			}
			// 记录类型
			recordType := ""
			if v, ok := cdrJSON["recordType"]; ok && v != nil {
				recordType = v.(string)
			}
			// 服务类型
			serviceType := ""
			if v, ok := cdrJSON["serviceType"]; ok && v != nil {
				serviceType = v.(string)
			}
			// 被叫
			called := ""
			if v, ok := cdrJSON["calledParty"]; ok && v != nil {
				called = v.(string)
			}
			// 主叫
			caller := ""
			if v, ok := cdrJSON["callerParty"]; ok && v != nil {
				caller = v.(string)
			}
			// 呼叫结果 0失败，1成功
			callResult := "FAILED"
			if v, ok := cdrJSON["result"]; ok && v != nil {
				resultVal := parse.Number(v)
				if resultVal == 1 {
					callResult = "SUCCESS"
				}
			}
			// 结果原因
			callCause := "UNKNOW ERROR"
			if v, ok := cdrJSON["cause"]; ok && v != nil {
				cause := fmt.Sprint(v)
				for _, v := range dictCDRSMSCCauseCode {
					if cause == v.DataValue {
						callCause = i18n.TKey(language, v.DataLabel)
						break
					}
				}
			}
			// 取时间
			timeStr := ""
			if v, ok := cdrJSON["updateTime"]; ok && v != nil {
				if releaseTime := parse.Number(v); releaseTime > 0 {
					timeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ)
				} else {
					timeStr = v.(string)
				}
			}

			dataCells = append(dataCells, map[string]any{
				"A" + idx: row.ID,
				"B" + idx: row.NeName,
				"C" + idx: recordType,
				"D" + idx: serviceType,
				"E" + idx: caller,
				"F" + idx: called,
				"G" + idx: callResult,
				"H" + idx: callCause,
				"I" + idx: timeStr,
			})
		}
		// 导出数据表格
		if err := file.WriterFileExecl(headerCells, dataCells, filePath, ""); err != nil {
			logger.Errorf("export operate log err => %v", err.Error())
			return "export err"
		}
	}

	// 上传到FTP服务器
	if err := s.backupService.FTPPushFile(filePath, "cdr"); err != nil {
		return "ok, ftp err:" + err.Error()
	}
	return "ok"
}

// exportSMF 导出SMF-CDR会话事件数据
func (s BackupExportCDRProcessor) exportSMF(query map[string]string, fileType string) string {
	neType := query["neType"]
	neTypeLower := strings.ToLower(neType)
	neId := query["neId"]
	endTime := parse.Number(query["endTime"])
	rows, total := s.cdrEventService.FindByPage(neType, query)
	if total == 0 {
		return "no data"
	}

	// 导出文件名称
	dateStr := date.ParseDateToStr(endTime, date.YYYYMMDDHHMMSS)
	fileName := fmt.Sprintf("%s_%s_cdr_export_%d_%s.%s", neTypeLower, neId, len(rows), dateStr, fileType)
	filePath := filepath.Join(s.backupService.BACKUP_DIR, fmt.Sprintf("/cdr/%s", neTypeLower), fileName)
	if runtime.GOOS == "windows" {
		filePath = fmt.Sprintf("C:%s", filePath)
	}

	if fileType == "csv" {
		// 转换数据
		data := [][]string{
			{
				"ID",
				"Charging ID",
				"NE Name",
				"Resource Unique ID",
				"Subscriber ID Data",
				"Subscriber ID Type",
				"Data Volume Uplink",
				"Data Volume Downlink",
				"Data Total Volume",
				"Duration",
				"Invocation Time",
				"User Identifier",
				"SSC Mode",
				"DNN ID",
				"PDU Type",
				"RAT Type",
				"PDU IPv4 Address",
				"Network Function IPv4",
				"PDU IPv6 Address Swith Prefix",
				"Record Network Function ID",
				"Record Type",
				"Record Opening Time",
			},
		}
		for _, row := range rows {
			// 解析 JSON 字符串为 map
			var cdrJSON map[string]interface{}
			err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON)
			if err != nil {
				logger.Warnf("CDRExport Error parsing JSON: %s", err.Error())
				continue
			}
			// 计费ID
			chargingID := ""
			if v, ok := cdrJSON["chargingID"]; ok && v != nil {
				chargingID = fmt.Sprint(parse.Number(v))
			}
			// 订阅 ID 类型
			subscriptionIDType := "-"
			// 订阅 ID 数据
			subscriptionIDData := "-"
			if v, ok := cdrJSON["subscriberIdentifier"]; ok && v != nil {
				if sub, subOk := v.(map[string]any); subOk && sub != nil {
					subscriptionIDType = sub["subscriptionIDType"].(string)
					subscriptionIDData = sub["subscriptionIDData"].(string)
				}
			}

			// 网络功能 IPv4 地址
			networkFunctionIPv4Address := ""
			if v, ok := cdrJSON["nFunctionConsumerInformation"]; ok && v != nil {
				if conInfo, conInfoOk := v.(map[string]any); conInfoOk && conInfo != nil {
					networkFunctionIPv4Address = conInfo["networkFunctionIPv4Address"].(string)
				}
			}

			// 数据量上行链路
			var dataVolumeUplink int64 = 0
			// 数据量下行链路
			var dataVolumeDownlink int64 = 0
			// 数据总量
			var dataTotalVolume int64 = 0
			if v, ok := cdrJSON["listOfMultipleUnitUsage"]; ok && v != nil {
				usageList := v.([]any)
				if len(usageList) > 0 {
					for _, used := range usageList {
						usedUnit := used.(map[string]any)
						usedUnitList := usedUnit["usedUnitContainer"].([]any)
						if len(usedUnitList) > 0 {
							for _, data := range usedUnitList {
								udata := data.(map[string]any)
								if dup, dupOk := udata["dataVolumeUplink"]; dupOk {
									dataVolumeUplink += parse.Number(dup)
								}
								if ddown, ddownOk := udata["dataVolumeDownlink"]; ddownOk {
									dataVolumeDownlink += parse.Number(ddown)
								}
								if dt, dtOk := udata["dataTotalVolume"]; dtOk {
									dataTotalVolume += parse.Number(dt)
								}
							}
						}
					}
				}
			}
			// 时长
			duration := "-"
			if v, ok := cdrJSON["duration"]; ok && v != nil {
				duration = fmt.Sprint(parse.Number(v))
			}
			// 调用时间
			invocationTimestamp := ""
			if v, ok := cdrJSON["invocationTimestamp"]; ok && v != nil {
				invocationTimestamp = v.(string)
			}
			// 记录打开时间
			User_Identifier := ""
			SSC_Mode := ""
			RAT_Type := ""
			DNN_ID := ""
			PDU_Type := ""
			PDU_IPv4 := ""
			PDU_IPv6 := ""
			if v, ok := cdrJSON["pDUSessionChargingInformation"]; ok && v != nil {
				pduInfo := v.(map[string]any)

				if v, ok := pduInfo["userIdentifier"]; ok && v != nil {
					User_Identifier = v.(string)
				}
				if v, ok := pduInfo["sSCMode"]; ok && v != nil {
					SSC_Mode = v.(string)
				}
				if v, ok := pduInfo["rATType"]; ok && v != nil {
					RAT_Type = v.(string)
				}
				if v, ok := pduInfo["dNNID"]; ok && v != nil {
					DNN_ID = v.(string)
				}
				if v, ok := pduInfo["pDUType"]; ok && v != nil {
					PDU_Type = v.(string)
				}
				if v, ok := pduInfo["pDUAddress"]; ok && v != nil {
					pDUAddress := v.(map[string]any)
					if addr, ok := pDUAddress["pDUIPv4Address"]; ok && addr != nil {
						PDU_IPv4 = addr.(string)
					}
					if addr, ok := pDUAddress["pDUIPv6AddresswithPrefix"]; ok && addr != nil {
						PDU_IPv6 = addr.(string)
					}
				}
			}

			// 记录网络参数ID
			recordNFID := ""
			if v, ok := cdrJSON["recordingNetworkFunctionID"]; ok && v != nil {
				recordNFID = v.(string)
			}

			//记录开始时间
			recordOpeningTime := ""
			if v, ok := cdrJSON["recordOpeningTime"]; ok && v != nil {
				recordOpeningTime = v.(string)
			}

			//记录类型
			recordType := ""
			if v, ok := cdrJSON["recordType"]; ok && v != nil {
				recordType = v.(string)
			}

			data = append(data, []string{
				fmt.Sprint(row.ID),
				chargingID,
				row.NeName,
				row.RmUid,
				subscriptionIDData,
				subscriptionIDType,
				fmt.Sprint(dataVolumeUplink),
				fmt.Sprint(dataVolumeDownlink),
				fmt.Sprint(dataTotalVolume),
				duration,
				invocationTimestamp,
				User_Identifier,
				SSC_Mode,
				DNN_ID,
				PDU_Type,
				RAT_Type,
				PDU_IPv4,
				networkFunctionIPv4Address,
				PDU_IPv6,
				recordNFID,
				recordType,
				recordOpeningTime,
			})
		}
		// 输出到文件
		if err := file.WriterFileCSV(data, filePath); err != nil {
			logger.Errorf("export operate log err => %v", err.Error())
			return "export err"
		}
	}

	if fileType == "xlsx" {
		// 第一行表头标题
		headerCells := map[string]string{
			"A1": "ID",
			"B1": "Charging ID",
			"C1": "NE Name",
			"D1": "Resource Unique ID",
			"E1": "Subscriber ID Data",
			"F1": "Subscriber ID Type",
			"G1": "Data Volume Uplink",
			"H1": "Data Volume Downlink",
			"I1": "Data Total Volume",
			"J1": "Duration",
			"K1": "Invocation Time",
			"L1": "User Identifier",
			"M1": "SSC Mode",
			"N1": "DNN ID",
			"O1": "PDU Type",
			"P1": "RAT Type",
			"Q1": "PDU IPv4 Address",
			"R1": "Network Function IPv4",
			"S1": "PDU IPv6 Address Swith Prefix",
			"T1": "Record Network Function ID",
			"U1": "Record Type",
			"V1": "Record Opening Time",
		}
		// 从第二行开始的数据
		dataCells := make([]map[string]any, 0)
		for i, row := range rows {
			idx := strconv.Itoa(i + 2)
			// 解析 JSON 字符串为 map
			var cdrJSON map[string]interface{}
			err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON)
			if err != nil {
				logger.Warnf("CDRExport Error parsing JSON: %s", err.Error())
				continue
			}
			// 计费ID
			chargingID := ""
			if v, ok := cdrJSON["chargingID"]; ok && v != nil {
				chargingID = fmt.Sprint(parse.Number(v))
			}
			// 订阅 ID 类型
			subscriptionIDType := "-"
			// 订阅 ID 数据
			subscriptionIDData := "-"
			if v, ok := cdrJSON["subscriberIdentifier"]; ok && v != nil {
				if sub, subOk := v.(map[string]any); subOk && sub != nil {
					subscriptionIDType = sub["subscriptionIDType"].(string)
					subscriptionIDData = sub["subscriptionIDData"].(string)
				}
			}

			// 网络功能 IPv4 地址
			networkFunctionIPv4Address := ""
			if v, ok := cdrJSON["nFunctionConsumerInformation"]; ok && v != nil {
				if conInfo, conInfoOk := v.(map[string]any); conInfoOk && conInfo != nil {
					networkFunctionIPv4Address = conInfo["networkFunctionIPv4Address"].(string)
				}
			}

			// 数据量上行链路
			var dataVolumeUplink int64 = 0
			// 数据量下行链路
			var dataVolumeDownlink int64 = 0
			// 数据总量
			var dataTotalVolume int64 = 0
			if v, ok := cdrJSON["listOfMultipleUnitUsage"]; ok && v != nil {
				usageList := v.([]any)
				if len(usageList) > 0 {
					for _, used := range usageList {
						usedUnit := used.(map[string]any)
						usedUnitList := usedUnit["usedUnitContainer"].([]any)
						if len(usedUnitList) > 0 {
							for _, data := range usedUnitList {
								udata := data.(map[string]any)
								if dup, dupOk := udata["dataVolumeUplink"]; dupOk {
									dataVolumeUplink += parse.Number(dup)
								}
								if ddown, ddownOk := udata["dataVolumeDownlink"]; ddownOk {
									dataVolumeDownlink += parse.Number(ddown)
								}
								if dt, dtOk := udata["dataTotalVolume"]; dtOk {
									dataTotalVolume += parse.Number(dt)
								}
							}
						}
					}
				}
			}
			// 时长
			duration := "-"
			if v, ok := cdrJSON["duration"]; ok && v != nil {
				duration = fmt.Sprint(parse.Number(v))
			}
			// 调用时间
			invocationTimestamp := ""
			if v, ok := cdrJSON["invocationTimestamp"]; ok && v != nil {
				invocationTimestamp = v.(string)
			}
			// 记录打开时间
			User_Identifier := ""
			SSC_Mode := ""
			RAT_Type := ""
			DNN_ID := ""
			PDU_Type := ""
			PDU_IPv4 := ""
			PDU_IPv6 := ""
			if v, ok := cdrJSON["pDUSessionChargingInformation"]; ok && v != nil {
				pduInfo := v.(map[string]any)

				if v, ok := pduInfo["userIdentifier"]; ok && v != nil {
					User_Identifier = v.(string)
				}
				if v, ok := pduInfo["sSCMode"]; ok && v != nil {
					SSC_Mode = v.(string)
				}
				if v, ok := pduInfo["rATType"]; ok && v != nil {
					RAT_Type = v.(string)
				}
				if v, ok := pduInfo["dNNID"]; ok && v != nil {
					DNN_ID = v.(string)
				}
				if v, ok := pduInfo["pDUType"]; ok && v != nil {
					PDU_Type = v.(string)
				}
				if v, ok := pduInfo["pDUAddress"]; ok && v != nil {
					pDUAddress := v.(map[string]any)
					if addr, ok := pDUAddress["pDUIPv4Address"]; ok && addr != nil {
						PDU_IPv4 = addr.(string)
					}
					if addr, ok := pDUAddress["pDUIPv6AddresswithPrefix"]; ok && addr != nil {
						PDU_IPv6 = addr.(string)
					}
				}
			}

			// 记录网络参数ID
			recordNFID := ""
			if v, ok := cdrJSON["recordingNetworkFunctionID"]; ok && v != nil {
				recordNFID = v.(string)
			}

			//记录开始时间
			recordOpeningTime := ""
			if v, ok := cdrJSON["recordOpeningTime"]; ok && v != nil {
				recordOpeningTime = v.(string)
			}

			//记录类型
			recordType := ""
			if v, ok := cdrJSON["recordType"]; ok && v != nil {
				recordType = v.(string)
			}

			dataCells = append(dataCells, map[string]any{
				"A" + idx: row.ID,
				"B" + idx: chargingID,
				"C" + idx: row.NeName,
				"D" + idx: row.RmUid,
				"E" + idx: subscriptionIDData,
				"F" + idx: subscriptionIDType,
				"G" + idx: dataVolumeUplink,
				"H" + idx: dataVolumeDownlink,
				"I" + idx: dataTotalVolume,
				"J" + idx: duration,
				"K" + idx: invocationTimestamp,
				"L" + idx: User_Identifier,
				"M" + idx: SSC_Mode,
				"N" + idx: DNN_ID,
				"O" + idx: PDU_Type,
				"P" + idx: RAT_Type,
				"Q" + idx: PDU_IPv4,
				"R" + idx: networkFunctionIPv4Address,
				"S" + idx: PDU_IPv6,
				"T" + idx: recordNFID,
				"U" + idx: recordType,
				"V" + idx: recordOpeningTime,
			})
		}
		// 导出数据表格
		if err := file.WriterFileExecl(headerCells, dataCells, filePath, ""); err != nil {
			logger.Errorf("export operate log err => %v", err.Error())
			return "export err"
		}
	}

	// 上传到FTP服务器
	if err := s.backupService.FTPPushFile(filePath, "cdr"); err != nil {
		return "ok, ftp err:" + err.Error()
	}
	return "ok"
}

// exportSGWC 导出SGWC-CDR会话事件数据
func (s BackupExportCDRProcessor) exportSGWC(query map[string]string, fileType string) string {
	neType := query["neType"]
	neTypeLower := strings.ToLower(neType)
	neId := query["neId"]
	endTime := parse.Number(query["endTime"])
	rows, total := s.cdrEventService.FindByPage(neType, query)
	if total == 0 {
		return "no data"
	}

	// 导出文件名称
	dateStr := date.ParseDateToStr(endTime, date.YYYYMMDDHHMMSS)
	fileName := fmt.Sprintf("%s_%s_cdr_export_%d_%s.%s", neTypeLower, neId, len(rows), dateStr, fileType)
	filePath := filepath.Join(s.backupService.BACKUP_DIR, fmt.Sprintf("/cdr/%s", neTypeLower), fileName)
	if runtime.GOOS == "windows" {
		filePath = fmt.Sprintf("C:%s", filePath)
	}

	if fileType == "csv" {
		// 转换数据
		data := [][]string{
			{
				"ID",
				"NE Name",
				"Resource Unique ID",
				"Charging ID",
				"IMSI",
				"MSISDN",
				"GPRS Uplink",
				"GPRS Downlink",
				"Duration",
				"Invocation Time",
				"PGW Address",
				"SGW Address",
				"RAT Type",
				"PDPPDN Type",
				"PDPPDN Address",
				"Node Address",
				"Node Type",
				"Record Access Point Name NI",
				"Record Cause For Rec Closing",
				"Record Sequence Number",
				"Local Record Sequence Number",
				"Record Type",
				"Record Opening Time",
			},
		}
		for _, row := range rows {
			// 解析 JSON 字符串为 map
			var cdrJSON map[string]interface{}
			err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON)
			if err != nil {
				logger.Warnf("CDRExport Error parsing JSON: %s", err.Error())
				continue
			}
			// 计费ID
			chargingID := ""
			if v, ok := cdrJSON["chargingID"]; ok && v != nil {
				chargingID = fmt.Sprint(parse.Number(v))
			}
			// IMSI
			servedIMSI := ""
			if v, ok := cdrJSON["servedIMSI"]; ok && v != nil {
				servedIMSI = fmt.Sprint(v)
			}
			// MSISDN
			servedMSISDN := ""
			if v, ok := cdrJSON["servedMSISDN"]; ok && v != nil {
				servedMSISDN = fmt.Sprint(v)
			}
			// pGWAddressUsed
			pGWAddressUsed := ""
			if v, ok := cdrJSON["pGWAddressUsed"]; ok && v != nil {
				pGWAddressUsed = fmt.Sprint(v)
				data[0][10] = "PGW Address"
			}
			if v, ok := cdrJSON["GGSNAddress"]; ok && v != nil {
				pGWAddressUsed = fmt.Sprint(v)
				data[0][10] = "GGSN Address"
			}
			// sGWAddress
			sGWAddress := ""
			if v, ok := cdrJSON["sGWAddress"]; ok && v != nil {
				sGWAddress = fmt.Sprint(v)
				data[0][11] = "SGW Address"
			}
			if v, ok := cdrJSON["SGSNAddress"]; ok && v != nil {
				sGWAddress = fmt.Sprint(v)
				data[0][11] = "SGSN Address"
			}
			// recordType
			recordType := ""
			if v, ok := cdrJSON["recordType"]; ok && v != nil {
				recordType = fmt.Sprint(v)
			}
			// rATType
			rATType := ""
			if v, ok := cdrJSON["rATType"]; ok && v != nil {
				rATType = fmt.Sprint(v)
			}
			// pdpPDNType
			pdpPDNType := ""
			if v, ok := cdrJSON["pdpPDNType"]; ok && v != nil {
				pdpPDNType = fmt.Sprint(v)
			}
			// servedPDPPDNAddress
			servedPDPPDNAddress := ""
			if v, ok := cdrJSON["servedPDPPDNAddress"]; ok && v != nil {
				servedPDPPDNAddress = fmt.Sprint(v)
			}
			// servedPDPPDNAddress
			servingNodeAddress := []string{}
			if v, ok := cdrJSON["servingNodeAddress"]; ok && v != nil {
				for _, v := range v.([]any) {
					servingNodeAddress = append(servingNodeAddress, fmt.Sprint(v))
				}
			}
			// servingNodeType
			servingNodeType := []string{}
			if v, ok := cdrJSON["servingNodeType"]; ok && v != nil {
				for _, v := range v.([]any) {
					if v, ok := v.(map[string]any)["servingNodeType"]; ok && v != nil {
						servingNodeType = append(servingNodeType, fmt.Sprint(v))
					}
				}
			}
			// accessPointNameNI
			accessPointNameNI := ""
			if v, ok := cdrJSON["accessPointNameNI"]; ok && v != nil {
				accessPointNameNI = fmt.Sprint(v)
			}
			// causeForRecClosing
			causeForRecClosing := ""
			if v, ok := cdrJSON["causeForRecClosing"]; ok && v != nil {
				causeForRecClosing = fmt.Sprint(v)
			}
			// recordSequenceNumber
			recordSequenceNumber := ""
			if v, ok := cdrJSON["recordSequenceNumber"]; ok && v != nil {
				recordSequenceNumber = fmt.Sprint(v)
			}
			// localRecordSequenceNumber
			localRecordSequenceNumber := ""
			if v, ok := cdrJSON["localRecordSequenceNumber"]; ok && v != nil {
				localRecordSequenceNumber = fmt.Sprint(v)
			}
			// 数据量上行链路
			var dataVolumeGPRSUplink int64 = 0
			// 数据量下行链路
			var dataVolumeGPRSDownlink int64 = 0
			if v, ok := cdrJSON["listOfTrafficVolumes"]; ok && v != nil {
				usageList := v.([]any)
				if len(usageList) > 0 {
					for _, used := range usageList {
						usedUnit := used.(map[string]any)
						if dup, dupOk := usedUnit["dataVolumeGPRSUplink"]; dupOk {
							dataVolumeGPRSUplink = parse.Number(dup)
						}
						if ddown, ddownOk := usedUnit["dataVolumeGPRSDownlink"]; ddownOk {
							dataVolumeGPRSDownlink = parse.Number(ddown)
						}
					}
				}
			}
			// 时长
			duration := "-"
			if v, ok := cdrJSON["duration"]; ok && v != nil {
				duration = fmt.Sprint(parse.Number(v))
			}
			// 调用时间
			invocationTimestamp := ""
			if v, ok := cdrJSON["recordOpeningTime"]; ok && v != nil {
				invocationTimestamp = v.(string)
			}

			data = append(data, []string{
				fmt.Sprint(row.ID),
				row.NeName,
				row.RmUid,
				chargingID,
				servedIMSI,
				servedMSISDN,
				fmt.Sprint(dataVolumeGPRSUplink),
				fmt.Sprint(dataVolumeGPRSDownlink),
				duration,
				invocationTimestamp,
				pGWAddressUsed,
				sGWAddress,
				rATType,
				pdpPDNType,
				servedPDPPDNAddress,
				strings.Join(servingNodeAddress, ","),
				strings.Join(servingNodeType, ","),
				accessPointNameNI,
				causeForRecClosing,
				recordSequenceNumber,
				localRecordSequenceNumber,
				recordType,
				invocationTimestamp,
			})
		}
		// 输出到文件
		if err := file.WriterFileCSV(data, filePath); err != nil {
			logger.Errorf("export operate log err => %v", err.Error())
			return "export err"
		}
	}

	if fileType == "xlsx" {
		// 第一行表头标题
		headerCells := map[string]string{
			"A1": "ID",
			"B1": "NE Name",
			"C1": "Resource Unique ID",
			"D1": "Charging ID",
			"E1": "IMSI",
			"F1": "MSISDN",
			"G1": "GPRS Uplink",
			"H1": "GPRS Downlink",
			"I1": "Duration",
			"J1": "Invocation Time",
			"K1": "PGW Address",
			"L1": "SGW Address",
			"M1": "RAT Type",
			"N1": "PDPPDN Type",
			"O1": "PDPPDN Address",
			"P1": "Node Address",
			"Q1": "Node Type",
			"R1": "Record Access Point Name NI",
			"S1": "Record Cause For Rec Closing",
			"T1": "Record Sequence Number",
			"U1": "Local Record Sequence Number",
			"V1": "Record Type",
			"W1": "Record Opening Time",
		}
		// 从第二行开始的数据
		dataCells := make([]map[string]any, 0)
		for i, row := range rows {
			idx := strconv.Itoa(i + 2)
			// 解析 JSON 字符串为 map
			var cdrJSON map[string]interface{}
			err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON)
			if err != nil {
				logger.Warnf("CDRExport Error parsing JSON: %s", err.Error())
				continue
			}
			// 计费ID
			chargingID := ""
			if v, ok := cdrJSON["chargingID"]; ok && v != nil {
				chargingID = fmt.Sprint(parse.Number(v))
			}
			// IMSI
			servedIMSI := ""
			if v, ok := cdrJSON["servedIMSI"]; ok && v != nil {
				servedIMSI = fmt.Sprint(v)
			}
			// MSISDN
			servedMSISDN := ""
			if v, ok := cdrJSON["servedMSISDN"]; ok && v != nil {
				servedMSISDN = fmt.Sprint(v)
			}
			// pGWAddressUsed
			pGWAddressUsed := ""
			if v, ok := cdrJSON["pGWAddressUsed"]; ok && v != nil {
				pGWAddressUsed = fmt.Sprint(v)
				headerCells["K1"] = "PGW Address"
			}
			if v, ok := cdrJSON["GGSNAddress"]; ok && v != nil {
				pGWAddressUsed = fmt.Sprint(v)
				headerCells["K1"] = "GGSN Address"
			}
			// sGWAddress
			sGWAddress := ""
			if v, ok := cdrJSON["sGWAddress"]; ok && v != nil {
				sGWAddress = fmt.Sprint(v)
				headerCells["L1"] = "SGW Address"
			}
			if v, ok := cdrJSON["SGSNAddress"]; ok && v != nil {
				sGWAddress = fmt.Sprint(v)
				headerCells["L1"] = "SGSN Address"
			}
			// recordType
			recordType := ""
			if v, ok := cdrJSON["recordType"]; ok && v != nil {
				recordType = fmt.Sprint(v)
			}
			// rATType
			rATType := ""
			if v, ok := cdrJSON["rATType"]; ok && v != nil {
				rATType = fmt.Sprint(v)
			}
			// pdpPDNType
			pdpPDNType := ""
			if v, ok := cdrJSON["pdpPDNType"]; ok && v != nil {
				pdpPDNType = fmt.Sprint(v)
			}
			// servedPDPPDNAddress
			servedPDPPDNAddress := ""
			if v, ok := cdrJSON["servedPDPPDNAddress"]; ok && v != nil {
				servedPDPPDNAddress = fmt.Sprint(v)
			}
			// servedPDPPDNAddress
			servingNodeAddress := []string{}
			if v, ok := cdrJSON["servingNodeAddress"]; ok && v != nil {
				for _, v := range v.([]any) {
					servingNodeAddress = append(servingNodeAddress, fmt.Sprint(v))
				}
			}
			// servingNodeType
			servingNodeType := []string{}
			if v, ok := cdrJSON["servingNodeType"]; ok && v != nil {
				for _, v := range v.([]any) {
					if v, ok := v.(map[string]any)["servingNodeType"]; ok && v != nil {
						servingNodeType = append(servingNodeType, fmt.Sprint(v))
					}
				}
			}
			// accessPointNameNI
			accessPointNameNI := ""
			if v, ok := cdrJSON["accessPointNameNI"]; ok && v != nil {
				accessPointNameNI = fmt.Sprint(v)
			}
			// causeForRecClosing
			causeForRecClosing := ""
			if v, ok := cdrJSON["causeForRecClosing"]; ok && v != nil {
				causeForRecClosing = fmt.Sprint(v)
			}
			// recordSequenceNumber
			recordSequenceNumber := ""
			if v, ok := cdrJSON["recordSequenceNumber"]; ok && v != nil {
				recordSequenceNumber = fmt.Sprint(v)
			}
			// localRecordSequenceNumber
			localRecordSequenceNumber := ""
			if v, ok := cdrJSON["localRecordSequenceNumber"]; ok && v != nil {
				localRecordSequenceNumber = fmt.Sprint(v)
			}
			// 数据量上行链路
			var dataVolumeGPRSUplink int64 = 0
			// 数据量下行链路
			var dataVolumeGPRSDownlink int64 = 0
			if v, ok := cdrJSON["listOfTrafficVolumes"]; ok && v != nil {
				usageList := v.([]any)
				if len(usageList) > 0 {
					for _, used := range usageList {
						usedUnit := used.(map[string]any)
						if dup, dupOk := usedUnit["dataVolumeGPRSUplink"]; dupOk {
							dataVolumeGPRSUplink = parse.Number(dup)
						}
						if ddown, ddownOk := usedUnit["dataVolumeGPRSDownlink"]; ddownOk {
							dataVolumeGPRSDownlink = parse.Number(ddown)
						}
					}
				}
			}
			// 时长
			duration := "-"
			if v, ok := cdrJSON["duration"]; ok && v != nil {
				duration = fmt.Sprint(parse.Number(v))
			}
			// 调用时间
			invocationTimestamp := ""
			if v, ok := cdrJSON["recordOpeningTime"]; ok && v != nil {
				invocationTimestamp = v.(string)
			}

			dataCells = append(dataCells, map[string]any{
				"A" + idx: row.ID,
				"B" + idx: row.NeName,
				"C" + idx: row.RmUid,
				"D" + idx: chargingID,
				"E" + idx: servedIMSI,
				"F" + idx: servedMSISDN,
				"G" + idx: dataVolumeGPRSUplink,
				"H" + idx: dataVolumeGPRSDownlink,
				"I" + idx: duration,
				"J" + idx: invocationTimestamp,
				"K" + idx: pGWAddressUsed,
				"L" + idx: sGWAddress,
				"M" + idx: rATType,
				"N" + idx: pdpPDNType,
				"O" + idx: servedPDPPDNAddress,
				"P" + idx: strings.Join(servingNodeAddress, ","),
				"Q" + idx: strings.Join(servingNodeType, ","),
				"R" + idx: accessPointNameNI,
				"S" + idx: causeForRecClosing,
				"T" + idx: recordSequenceNumber,
				"U" + idx: localRecordSequenceNumber,
				"V" + idx: recordType,
				"W" + idx: invocationTimestamp,
			})
		}
		// 导出数据表格
		if err := file.WriterFileExecl(headerCells, dataCells, filePath, ""); err != nil {
			logger.Errorf("export sgec cdr err => %v", err.Error())
			return "export err"
		}
	}

	// 上传到FTP服务器
	if err := s.backupService.FTPPushFile(filePath, "cdr"); err != nil {
		return "ok, ftp err:" + err.Error()
	}
	return "ok"
}
