package backup_export_table

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

	"be.ems/src/framework/cron"
	"be.ems/src/framework/database/db"
	"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"
	neDataService "be.ems/src/modules/ne_data/service"
	systemModel "be.ems/src/modules/system/model"
	systemService "be.ems/src/modules/system/service"
)

var NewProcessor = &BackupExportTableProcessor{
	backupService:   neDataService.NewBackup,
	cdrEventService: neDataService.NewCDREvent,
	count:           0,
}

// BackupExportTable 备份导出数据表
type BackupExportTableProcessor struct {
	backupService   *neDataService.Backup   // 备份相关服务
	cdrEventService *neDataService.CDREvent // CDR会话事件服务
	count           int                     // 执行次数
}

func (s *BackupExportTableProcessor) 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 {
		Hour       int      `json:"hour"`       // 数据时间从任务执行时间前的小时数
		TableName  string   `json:"tableName"`  // 数据表名
		Columns    []string `json:"columns"`    // 支持字段
		BackupPath string   `json:"backupPath"` // 备份输出路径 /usr/local/omc/backup/{backupPath}
	}
	err := json.Unmarshal([]byte(sysJob.TargetParams), &params)
	if err != nil {
		return nil, err
	}

	var affected int64
	var errMsg error
	fileName := fmt.Sprintf("%s_export_%s.csv", strings.ToLower(params.TableName), time.Now().Format("20060102150405"))
	filePath := filepath.Join("/usr/local/omc/backup", params.BackupPath, fileName)
	if runtime.GOOS == "windows" {
		filePath = fmt.Sprintf("C:%s", filePath)
	}
	switch params.TableName {
	case "sys_log_operate":
		affected, errMsg = s.exportSysLogOperate(params.Hour, params.Columns, filePath)
	case "cdr_event_smsc":
		affected, errMsg = s.exportSMSC(params.Hour, params.Columns, filePath)
	case "cdr_event_ims":
		affected, errMsg = s.exportIMS(params.Hour, params.Columns, filePath)
	case "cdr_event_smf":
		affected, errMsg = s.exportSMF(params.Hour, params.Columns, filePath)
	case "cdr_event_sgwc":
		affected, errMsg = s.exportSGWC(params.Hour, params.Columns, filePath)
	}
	if errMsg != nil {
		return nil, errMsg
	}

	// 上传到FTP服务器
	if affected > 0 {
		if err := s.backupService.FTPPushFile(filePath, params.BackupPath); err != nil {
			result["ftpErr"] = err.Error()
		}
	}
	result["affected"] = affected

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

// exportSysLogOperate 导出csv
func (s BackupExportTableProcessor) exportSysLogOperate(hour int, columns []string, filePath string) (int64, error) {
	// 前 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(hour) * time.Hour)

	// 查询数据
	rows := []systemModel.SysLogOperate{}
	tx := db.DB("").Model(&systemModel.SysLogOperate{})
	tx = tx.Where("opera_time >= ? and opera_time <= ?", start.UnixMilli(), end.UnixMilli())
	if err := tx.Find(&rows).Error; err != nil {
		return 0, err
	}
	if len(rows) <= 0 {
		return 0, nil
	}
	language := "en"
	// 写入csv
	data := [][]string{}
	data = append(data, columns)
	for _, row := range rows {
		// 业务类型
		businessType := ""
		switch row.BusinessType {
		case "0":
			// 业务操作类型-其它
			businessType = i18n.TKey(language, "dictData.operType.other")
		case "1":
			// 业务操作类型-新增
			businessType = i18n.TKey(language, "dictData.operType.add")
		case "2":
			// 业务操作类型-修改
			businessType = i18n.TKey(language, "dictData.operType.edit")
		case "3":
			// 业务操作类型-删除
			businessType = i18n.TKey(language, "dictData.operType.delete")
		case "4":
			// 业务操作类型-授权
			businessType = i18n.TKey(language, "dictData.operType.auth")
		case "5":
			// 业务操作类型-导出
			businessType = i18n.TKey(language, "dictData.operType.export")
		case "6":
			// 业务操作类型-导入
			businessType = i18n.TKey(language, "dictData.operType.import")
		case "7":
			// 业务操作类型-强退
			businessType = i18n.TKey(language, "dictData.operType.forced quit")
		case "8":
			// 业务操作类型-清空数据
			businessType = i18n.TKey(language, "dictData.operType.clear")
		}

		// 状态
		statusValue := i18n.TKey(language, "dictData.fail")
		if row.StatusFlag == "1" {
			statusValue = i18n.TKey(language, "dictData.success")
		}

		arr := make([]string, len(columns))
		for i, col := range columns {
			if col == "id" {
				arr[i] = fmt.Sprintf("%d", row.ID)
			}
			if col == "title" {
				arr[i] = fmt.Sprintf("%v", row.Title)
			}
			if col == "businessType" || col == "business_type" {
				arr[i] = fmt.Sprintf("%v", businessType)
			}
			if col == "operaBy" || col == "opera_by" {
				arr[i] = fmt.Sprintf("%v", row.OperaBy)
			}
			if col == "operaUrlMethod" || col == "opera_url_method" {
				arr[i] = fmt.Sprintf("%v", row.OperaUrlMethod)
			}
			if col == "operaUrl" || col == "opera_url" {
				arr[i] = fmt.Sprintf("%v", row.OperaUrl)
			}
			if col == "operaIp" || col == "opera_ip" {
				arr[i] = fmt.Sprintf("%v", row.OperaIp)
			}
			if col == "statusValue" || col == "status" {
				arr[i] = fmt.Sprintf("%v", statusValue)
			}
			if col == "operaTime" || col == "opera_time" {
				arr[i] = fmt.Sprintf("%v", date.ParseDateToStr(row.OperaTime, date.YYYY_MM_DDTHH_MM_SSZ))
			}
			if col == "costTime" || col == "cost_time" {
				arr[i] = fmt.Sprintf("%v", row.CostTime)
			}
		}
		data = append(data, arr)
	}

	err := file.WriterFileCSV(data, filePath)

	return tx.RowsAffected, err
}

// exportSMF 导出csv
func (s BackupExportTableProcessor) exportSMF(hour int, columns []string, filePath string) (int64, error) {
	// 前 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(hour) * time.Hour)

	// 查询数据
	rows, total := s.cdrEventService.FindByPage("SMF", map[string]string{
		"sortField": "created_at",
		"sortOrder": "asc",
		"beginTime": fmt.Sprint(start.UnixMilli()),
		"endTime":   fmt.Sprint(end.UnixMilli()),
	})
	if total <= 0 {
		return 0, nil
	}

	// 写入csv
	data := [][]string{}
	data = append(data, columns)
	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)
		}

		arr := make([]string, len(columns))
		for i, col := range columns {
			if col == "id" {
				arr[i] = fmt.Sprintf("%d", row.ID)
			}
			if col == "neName" || col == "ne_name" {
				arr[i] = fmt.Sprintf("%v", row.NeName)
			}
			// 单层json
			if strings.HasPrefix("json", col) {
				key := strings.TrimPrefix(col, "json")
				if v, ok := cdrJSON[key]; ok && v != nil {
					arr[i] = fmt.Sprintf("%v", v)
				}
			}

			// 计费ID
			if col == "chargingID" || col == "charging_id" {
				arr[i] = fmt.Sprintf("%v", chargingID)
			}
			if col == "subscriptionIDData" || col == "subscription_id_data" {
				arr[i] = fmt.Sprintf("%v", subscriptionIDData)
			}
			if col == "subscriptionIDType" || col == "subscription_id_type" {
				arr[i] = fmt.Sprintf("%v", subscriptionIDType)
			}
			if col == "dataVolumeUplink" || col == "data_volume_uplink" {
				arr[i] = fmt.Sprintf("%v", dataVolumeUplink)
			}
			if col == "dataVolumeDownlink" || col == "data_volume_downlink" {
				arr[i] = fmt.Sprintf("%v", dataVolumeDownlink)
			}
			if col == "dataTotalVolume" || col == "data_total_volume" {
				arr[i] = fmt.Sprintf("%v", dataTotalVolume)
			}
			if col == "duration" {
				arr[i] = fmt.Sprintf("%v", duration)
			}
			if col == "invocationTimestamp" || col == "invocation_timestamp" {
				arr[i] = fmt.Sprintf("%v", invocationTimestamp)
			}
			if col == "userIdentifier" || col == "user_identifier" {
				arr[i] = fmt.Sprintf("%v", User_Identifier)
			}
			if col == "sscMode" || col == "ssc_mode" {
				arr[i] = fmt.Sprintf("%v", SSC_Mode)
			}
			if col == "dnnId" || col == "dnn_id" {
				arr[i] = fmt.Sprintf("%v", DNN_ID)
			}
			if col == "pduType" || col == "pdu_type" {
				arr[i] = fmt.Sprintf("%v", PDU_Type)
			}
			if col == "ratType" || col == "rat_type" {
				arr[i] = fmt.Sprintf("%v", RAT_Type)
			}
			if col == "pduIpv4" || col == "pdu_ipv4" {
				arr[i] = fmt.Sprintf("%v", PDU_IPv4)
			}
			if col == "pduIpv6" || col == "pdu_ipv6" {
				arr[i] = fmt.Sprintf("%v", PDU_IPv6)
			}
			if col == "networkFunctionIPv4Address" || col == "network_function_ipv4_address" {
				arr[i] = fmt.Sprintf("%v", networkFunctionIPv4Address)
			}
			if col == "recordNFID" || col == "record_nfId" {
				arr[i] = fmt.Sprintf("%v", recordNFID)
			}
			if col == "recordType" || col == "record_type" {
				arr[i] = fmt.Sprintf("%v", recordType)
			}
			if col == "recordOpeningTime" || col == "record_opening_time" {
				arr[i] = fmt.Sprintf("%v", recordOpeningTime)
			}
		}
		data = append(data, arr)
	}

	err := file.WriterFileCSV(data, filePath)

	return total, err
}

// exportIMS 导出csv
func (s BackupExportTableProcessor) exportIMS(hour int, columns []string, filePath string) (int64, error) {
	// 前 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(hour) * time.Hour)

	// 查询数据
	rows, total := s.cdrEventService.FindByPage("IMS", map[string]string{
		"sortField": "created_at",
		"sortOrder": "asc",
		"beginTime": fmt.Sprint(start.UnixMilli()),
		"endTime":   fmt.Sprint(end.UnixMilli()),
	})
	if total <= 0 {
		return 0, nil
	}

	// 读取字典数据 CDR SIP响应代码类别类型
	dictCDRSipCode := systemService.NewSysDictData.FindByType("cdr_sip_code")
	// 读取字典数据 CDR 呼叫类型
	dictCDRCallType := systemService.NewSysDictData.FindByType("cdr_call_type")
	language := "en" // 语言

	// 写入csv
	data := [][]string{}
	data = append(data, columns)
	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
		}

		arr := make([]string, len(columns))
		for i, col := range columns {
			if col == "id" {
				arr[i] = fmt.Sprintf("%d", row.ID)
			}
			if col == "neName" || col == "ne_name" {
				arr[i] = fmt.Sprintf("%v", row.NeName)
			}
			// 单层json
			if strings.HasPrefix("json", col) {
				key := strings.TrimPrefix(col, "json")
				if v, ok := cdrJSON[key]; ok && v != nil {
					arr[i] = fmt.Sprintf("%v", v)
				}
			}

			// 记录类型
			if col == "recordType" || col == "record_type" {
				if v, ok := cdrJSON["recordType"]; ok && v != nil {
					arr[i] = fmt.Sprintf("%v", v)
				}
			}

			// 呼叫类型
			callType := "sms"
			if col == "callType" || col == "call_type" {
				if v, ok := cdrJSON["callType"]; ok && v != nil {
					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
							}
						}
					}
					arr[i] = fmt.Sprintf("%v", callTypeLable)
				}
			}

			// 被叫
			if col == "calledParty" || col == "called_party" {
				if v, ok := cdrJSON["calledParty"]; ok && v != nil {
					arr[i] = fmt.Sprintf("%v", v)
				}
			}
			// 主叫
			if col == "callerParty" || col == "caller_party" {
				if v, ok := cdrJSON["callerParty"]; ok && v != nil {
					arr[i] = fmt.Sprintf("%v", v)
				}
			}
			// 时长
			if col == "callDuration" || col == "call_duration" {
				if v, ok := cdrJSON["callDuration"]; ok && v != nil {
					arr[i] = fmt.Sprintf("%ds", parse.Number(v))
				}
			}
			// 呼叫结果 非短信都有code作为结果 sms短信都ok
			if col == "cause" {
				if callType == "sms" {
					arr[i] = "Success"
				} else {
					callResult := "Other"
					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
							}
						}
					}
					arr[i] = callResult
				}
			}
			// 呼叫时间
			if col == "seizureTime" || col == "seizure_time" {
				if v, ok := cdrJSON["seizureTime"]; ok && v != nil {
					if seizureTime := parse.Number(v); seizureTime > 0 {
						arr[i] = date.ParseDateToStr(seizureTime, date.YYYY_MM_DDTHH_MM_SSZ)
					} else {
						arr[i] = fmt.Sprintf("%v", v)
					}

				}
			}
			// 挂断时间
			if col == "releaseTime" || col == "release_time" {
				if v, ok := cdrJSON["releaseTime"]; ok && v != nil {
					if seizureTime := parse.Number(v); seizureTime > 0 {
						arr[i] = date.ParseDateToStr(seizureTime, date.YYYY_MM_DDTHH_MM_SSZ)
					} else {
						arr[i] = fmt.Sprintf("%v", v)
					}

				}
			}
		}
		data = append(data, arr)
	}

	err := file.WriterFileCSV(data, filePath)

	return total, err
}

// exportSMSC 导出csv
func (s BackupExportTableProcessor) exportSMSC(hour int, columns []string, filePath string) (int64, error) {
	// 前 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(hour) * time.Hour)

	// 查询数据
	rows, total := s.cdrEventService.FindByPage("SMS", map[string]string{
		"sortField": "created_at",
		"sortOrder": "asc",
		"beginTime": fmt.Sprint(start.UnixMilli()),
		"endTime":   fmt.Sprint(end.UnixMilli()),
	})
	if total <= 0 {
		return 0, nil
	}

	// 读取字典数据 CDR 原因码
	dictCDRCauseCode := systemService.NewSysDictData.FindByType("cdr_cause_code")
	language := "en"

	// 写入csv
	data := [][]string{}
	data = append(data, columns)
	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 := "Fail"
		if v, ok := cdrJSON["result"]; ok && v != nil {
			resultVal := parse.Number(v)
			if resultVal == 1 {
				callResult = "Success"
			}
		}
		// 结果原因
		if v, ok := cdrJSON["cause"]; ok && v != nil && callResult == "Fail" {
			cause := fmt.Sprint(v)
			for _, v := range dictCDRCauseCode {
				if cause == v.DataValue {
					callResult = fmt.Sprintf("%s, %s", callResult, 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)
			}
		}

		arr := make([]string, len(columns))
		for i, v := range columns {
			if v == "id" {
				arr[i] = fmt.Sprintf("%d", row.ID)
			}
			if v == "neName" || v == "ne_name" {
				arr[i] = fmt.Sprintf("%v", row.NeName)
			}
			// 单层json
			if strings.HasPrefix("json", v) {
				key := strings.TrimPrefix(v, "json")
				if v, ok := cdrJSON[key]; ok && v != nil {
					arr[i] = fmt.Sprintf("%v", v)
				}
			}

			if v == "recordType" || v == "record_type" {
				arr[i] = fmt.Sprintf("%v", recordType)
			}
			if v == "serviceType" || v == "service_type" {
				arr[i] = fmt.Sprintf("%v", serviceType)
			}
			if v == "callerParty" || v == "caller_party" {
				arr[i] = fmt.Sprintf("%v", caller)
			}
			if v == "calledParty" || v == "called_party" {
				arr[i] = fmt.Sprintf("%v", called)
			}
			if v == "result" {
				arr[i] = fmt.Sprintf("%v", callResult)
			}
			if v == "updateTime" || v == "update_time" {
				arr[i] = fmt.Sprintf("%v", timeStr)
			}
		}
		data = append(data, arr)
	}

	err := file.WriterFileCSV(data, filePath)

	return total, err
}

// exportSGWC 导出csv
func (s BackupExportTableProcessor) exportSGWC(hour int, columns []string, filePath string) (int64, error) {
	// 前 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(hour) * time.Hour)

	// 查询数据
	rows, total := s.cdrEventService.FindByPage("SGWC", map[string]string{
		"sortField": "created_at",
		"sortOrder": "asc",
		"beginTime": fmt.Sprint(start.UnixMilli()),
		"endTime":   fmt.Sprint(end.UnixMilli()),
	})
	if total <= 0 {
		return 0, nil
	}

	// 写入csv
	data := [][]string{}
	data = append(data, columns)
	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)
		}
		if v, ok := cdrJSON["GGSNAddress"]; ok && v != nil {
			pGWAddressUsed = fmt.Sprint(v)
		}
		// sGWAddress
		sGWAddress := ""
		if v, ok := cdrJSON["sGWAddress"]; ok && v != nil {
			sGWAddress = fmt.Sprint(v)
		}
		if v, ok := cdrJSON["SGSNAddress"]; ok && v != nil {
			sGWAddress = fmt.Sprint(v)
		}
		// 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)
		}

		arr := make([]string, len(columns))
		for i, v := range columns {
			if v == "id" {
				arr[i] = fmt.Sprintf("%d", row.ID)
			}
			if v == "neName" || v == "ne_name" {
				arr[i] = fmt.Sprintf("%v", row.NeName)
			}
			// 单层json
			if strings.HasPrefix("json", v) {
				key := strings.TrimPrefix(v, "json")
				if v, ok := cdrJSON[key]; ok && v != nil {
					arr[i] = fmt.Sprintf("%v", v)
				}
			}

			if v == "chargingID" || v == "charging_id" {
				arr[i] = fmt.Sprintf("%v", chargingID)
			}
			if v == "servedIMSI" || v == "served_imsi" {
				arr[i] = fmt.Sprintf("%v", servedIMSI)
			}
			if v == "servedMSISDN" || v == "served_msisdn" {
				arr[i] = fmt.Sprintf("%v", servedMSISDN)
			}
			if v == "dataVolumeGPRSUplink" || v == "data_volume_gprs_uplink" {
				arr[i] = fmt.Sprintf("%v", dataVolumeGPRSUplink)
			}
			if v == "dataVolumeGPRSDownlink" || v == "data_volume_gprs_downlink" {
				arr[i] = fmt.Sprintf("%v", dataVolumeGPRSDownlink)
			}
			if v == "duration" {
				arr[i] = fmt.Sprintf("%v", duration)
			}
			if v == "invocationTimestamp" || v == "invocation_timestamp" {
				arr[i] = fmt.Sprintf("%v", invocationTimestamp)
			}
			if v == "pgwAddressUsed" || v == "pgw_address_used" {
				arr[i] = fmt.Sprintf("%v", pGWAddressUsed)
			}
			if v == "GGSNAddress" || v == "ggsn_address" {
				arr[i] = fmt.Sprintf("%v", pGWAddressUsed)
			}
			if v == "sgwAddress" || v == "sgw_address" {
				arr[i] = fmt.Sprintf("%v", sGWAddress)
			}
			if v == "SGSNAddress" || v == "sgsn_address" {
				arr[i] = fmt.Sprintf("%v", sGWAddress)
			}
			if v == "ratType" || v == "rat_type" {
				arr[i] = fmt.Sprintf("%v", rATType)
			}
			if v == "pdpPDNType" || v == "pdp_pdn_type" {
				arr[i] = fmt.Sprintf("%v", pdpPDNType)
			}
			if v == "servedPDPPDNAddress" || v == "served_pdppdn_address" {
				arr[i] = fmt.Sprintf("%v", servedPDPPDNAddress)
			}
			if v == "servingNodeAddress" || v == "serving_node_address" {
				arr[i] = fmt.Sprintf("%v", strings.Join(servingNodeAddress, ","))
			}
			if v == "servingNodeType" || v == "serving_node_type" {
				arr[i] = fmt.Sprintf("%v", strings.Join(servingNodeType, ","))
			}
			if v == "accessPointNameNI" || v == "access_point_name_ni" {
				arr[i] = fmt.Sprintf("%v", accessPointNameNI)
			}
			if v == "causeForRecClosing" || v == "cause_for_rec_closing" {
				arr[i] = fmt.Sprintf("%v", causeForRecClosing)
			}
			if v == "recordSequenceNumber" || v == "record_sequence_number" {
				arr[i] = fmt.Sprintf("%v", recordSequenceNumber)
			}
			if v == "localRecordSequenceNumber" || v == "local_record_sequence_number" {
				arr[i] = fmt.Sprintf("%v", localRecordSequenceNumber)
			}
			if v == "recordType" || v == "record_type" {
				arr[i] = fmt.Sprintf("%v", recordType)
			}
			if v == "recordOpeningTime" || v == "record_opening_time" {
				arr[i] = fmt.Sprintf("%v", invocationTimestamp)
			}
		}
		data = append(data, arr)
	}

	err := file.WriterFileCSV(data, filePath)

	return total, err
}
