package common

import (
	"fmt"
	"nms_nbi/src/framework/config"
	"nms_nbi/src/framework/utils/date"
	"nms_nbi/src/framework/utils/file"
	"nms_nbi/src/modules/api_rest_cxy/utils/oss"
	"path/filepath"
	"strings"
	"time"
)

// DataSaveFileName 数据文件命名要求
//
// 资源数据文件、性能数据文件的命名规则如下：
// <资源对象类型简称>-<数据版本>-<数据时间>-<日志类型>-<同步请求标识>-<Ri>-<序列号>.<后缀>
// 告警同步数据文件、配置数据文件、日志数据文件的命名规则如下：
// <网元资源对象RUID中的“资源对象编号”>-<数据版本>-<数据时间>-<日志类型>-<同步请求标识>-<Ri>-<序列号>.<后缀>
//
// –resCode 资源对象类型简称、网元资源对象RUID中的“资源对象编号”：参考本文档附件1。
// –version 数据版本：遵循数据模型规范版本，允许同一目录下存放不同版本的数据文件。
// –dateStr 数据时间：采用YYYYMMDDHH24MMSS格式。资源、告警、配置、日志数据为数据文件开始生成时间，其中资源数据文件和配置数据文件周期性上报，生成时间为每天的0点和12点；性能数据为统计周期的起始时间，周期性上报，周期为15分钟。
// –logType 日志类型：可选，只针对日志文件，包括operate（操作日志）、security(安全日志)、other（其他）。
// –requestId 同步请求标识：可选，仅在告警文件同步时使用，用于唯一标识一次同步请求。标识规则是“请求操作ID”。“请求操作ID”是同步请求消息中消息序号（requestId）。
// –Ri：可选。当接口数据文件内容有误（如数据缺失等）时，OMC重新生成文件提供给NMS进行数据补采，新文件增加“Ri”进行标识，i从1开始，每重新生成一次i加1。
// –Num 序列号：可选。当文件总量小于100MB(允许上下浮动10%)时，应只形成一个文件；当文件总量大于100MB(允许上下浮动10%)时要求进行文件分割，即分割后的文件大小（除最后一个）均应介于（90MB,110MB）之间。分割后的文件增加序列号标识，序列号为三位，取值为001-999。在文件切分过程中，不能把一条完整的记录切开放到两个文件中。
// –suffix 后缀：每个文件都进行压缩，统一采用zip或gzip压缩，压缩文件后缀是zip或gz。对于压缩前的JSON格式文件，后缀为JSON。
//
// 文件名示例：
// 资源文件：CLL-V1.0-20151227000000-001.zip
// 性能文件：CLL-V1.0-20151227000000-001.zip
// 告警文件：0000000001153492-V1.0-20150611011603-001.zip
// 日志文件：0000000001153492-V1.0-20150611011603-operate.zip
// 配置文件：0000000001153492-V1.0-20150611011600.zip
type DataSaveFileName struct {
	ResCode   string // 资源对象类型简称(资源数据文件、性能数据文件) => 网元类型 资源对象编号(告警同步数据文件、配置数据文件、日志数据文件) => 设备序列号
	Version   string // 数据版本 => 网元版本 固定1.0
	DateStr   string // 数据时间 采用YYYYMMDDHH24MMSS格式
	LogType   string // 可选 日志类型 只针对日志文件，包括operate（操作日志）、security(安全日志)、other（其他）
	RequestId string // 可选 同步请求标识 仅在告警文件同步时使用
	Ri        string // 可选 数据补采 当接口数据文件内容有误（如数据缺失等）时
	Num       string // 可选 序列号 当文件总量大于100MB进行分割，之后的文件增加序列号标识，序列号为三位，取值为001-999
}

// join 将参数进行连接-分隔
func (s *DataSaveFileName) join() string {
	nameArr := []string{}

	if s.ResCode != "" {
		nameArr = append(nameArr, s.ResCode)
	} else {
		serialNumber := config.Get("cxy.serialNumber").(string)
		serialNumber = fmt.Sprintf("%0*s", 16, serialNumber)
		nameArr = append(nameArr, serialNumber)
	}

	if s.Version != "" {
		nameArr = append(nameArr, "V"+s.Version)
	} else {
		nameArr = append(nameArr, "V1.0")
	}

	if s.DateStr != "" {
		nameArr = append(nameArr, s.DateStr)
	} else {
		nameArr = append(nameArr, date.ParseDateToStr(time.Now(), date.YYYYMMDDHHMMSS))
	}

	if s.LogType != "" {
		nameArr = append(nameArr, s.LogType)
	}
	if s.RequestId != "" {
		nameArr = append(nameArr, s.RequestId)
	}
	if s.Ri != "" {
		nameArr = append(nameArr, s.Ri)
	}
	if s.Num != "" {
		nameArr = append(nameArr, s.Num)
	}
	return strings.Join(nameArr, "-")
}

// JSON 生成json后缀文件名
func (s *DataSaveFileName) JSON() string {
	filename := s.join()
	return fmt.Sprintf("%s.json", filename)
}

// ZIP 生成zip后缀文件名
func (s *DataSaveFileName) ZIP() string {
	filename := s.join()
	return fmt.Sprintf("%s.zip", filename)
}

// CSV 生成csv后缀文件名
func (s *DataSaveFileName) CSV() string {
	filename := s.join()
	return fmt.Sprintf("%s.csv", filename)
}

// DataSaveFilePath 文件数据保存路径
//
// 文件数据集中存储在云平台所提供的对象存储数据库OSS中。文件数据保存路径如下：
// 路径说明：/专业编码/OMC厂商编码/OMC编号/网元类型/数据类别/时间
// –专业编码、OMC厂商编码、OMC编号、网元类型：请参考本文档附件1。
// –数据类别：NRM（资源）/ PM（性能）/CM（配置）/FM（告警）/LOG（日志）。
// –时间：资源、告警、配置、日志数据按天存放，时间格式为YYYYMMDD；性能数据按小时存放，时间格式为YYYYMMDDHH24，小时数为性能数据统计起始时间。
func DataSaveFilePath(neType, dataType string) string {
	basePath := BasePath("/")
	dateStr := date.ParseDateToStr(time.Now(), "20060102")
	if dataType == "PM" {
		dateStr = date.ParseDateToStr(time.Now(), "200601021504")
	}
	return fmt.Sprintf("%s/%s/%s/%s", basePath, neType, dataType, dateStr)
}

// BasePath 基础路径 separator 分隔符
//
// 专业编码{separator}OMC厂商编码{separator}OMC编号
func BasePath(separator string) string {
	professionCode := config.Get("cxy.professionCode").(string)
	vendorCode := config.Get("cxy.vendorCode").(string)
	omcCode := config.Get("cxy.omcCode").(string)
	return fmt.Sprintf("%s%s%s%s%s", professionCode, separator, vendorCode, separator, omcCode)
}

// UploadOSSByJSONToZip 将json文件压缩zip上传到oss
func UploadOSSByJSONToZip(filePath, neType, dataType string) error {
	dirPath := DataSaveFilePath(neType, dataType)
	// 添加到zip压缩文件
	zipFilePath := strings.Replace(filePath, ".json", ".zip", 1)
	err := file.CompressZipByFile(zipFilePath, filePath)
	if err != nil {
		return err
	}
	// 组成上传文件路径名
	zipFileName := filepath.Base(zipFilePath)
	newFileName := fmt.Sprintf("%s/%s", dirPath, zipFileName)
	oss.FileUploadFileByFilePath(zipFilePath, newFileName)
	return nil
}

// UploadOSSByZip 将zip文件上传到oss
func UploadOSSByZip(filePath, neType, dataType string) error {
	dirPath := DataSaveFilePath(neType, dataType)
	// 组成上传文件路径名
	zipFileName := filepath.Base(filePath)
	newFileName := fmt.Sprintf("%s/%s", dirPath, zipFileName)
	oss.FileUploadFileByFilePath(filePath, newFileName)
	return nil
}
