package sqlSync

import (
	"fmt"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
	"sync"

	"goutil/fileUtil"
	"goutil/logUtil"
)

const (
	// 第一个文件名
	con_Default_FileName = "00000000"

	// 文件名后缀
	con_FileName_Suffix = "data"
)

// 同步数据对象(用于往文件中写入sql语句)
type SqlFile struct {
	// 存放同步数据的文件夹路径
	dirPath string

	// 同步数据对象的唯一标识，用于进行重复判断
	identifier string

	// 保存数据的大文件对象
	bigFileObj *fileUtil.BigFile

	// 数据同步对象
	mutex sync.Mutex
}

// 将数据写入同步数据对象
// data:待写入的数据
func (this *SqlFile) Write(data string) {
	this.mutex.Lock()
	defer this.mutex.Unlock()

	// 写入数据
	err := Write(this.bigFileObj, data)
	if err != nil {
		prefix := fmt.Sprintf("%s-%s", this.identifier, "SqlFile.write.bigFileObj.WriteMessage")
		err = fmt.Errorf("%s-Write message to big file object failed:%s", prefix, err)
		logUtil.ErrorLog(err.Error())
		panic(err)
	}
}

// 获取大文件对象的文件绝对路径
func (this *SqlFile) FileFullName() string {
	return filepath.Join(this.dirPath, this.bigFileObj.FileName())
}

// 当前读写的文件名
func (this *SqlFile) FileName() string {
	return this.bigFileObj.FileName()
}

// 创建同步数据对象
// _dirPath:目录的路径
// _identifier:当前数据的唯一标识（可以使用数据库表名）
// _maxFileSize:每个大文件的最大写入值（单位：Byte）
// 返回值:
// 同步数据对象
func NewSqlFile(dirPath, identifier, fileName string, maxFileSize int) *SqlFile {
	result := &SqlFile{
		dirPath:    dirPath,
		identifier: identifier,
	}

	// 初始化大文件对象
	if fileName == "" {
		fileName = con_Default_FileName
	}
	bigFileObj, err := fileUtil.NewBigFileWithNewFileNameFunc2(dirPath, "", fileName, maxFileSize, NewFileName)
	if err != nil {
		prefix := fmt.Sprintf("%s-%s", result.identifier, "SqlFile.newSqlFile.fileUtil.NewBigFileWithNewFileNameFunc")
		err = fmt.Errorf("%s-Create big file object failed:%s", prefix, err)
		logUtil.ErrorLog(err.Error())
		panic(err)
	}
	result.bigFileObj = bigFileObj

	return result
}

// 根据当前文件名生成下一个sql文件名
// prefix:文件名前缀
// path:当前文件的路径
// 返回值:
// string:下一个文件的完整路径
func NewFileName(prefix, path string) string {
	fullName := filepath.Base(path)
	curFileName := strings.Split(fullName, ".")[0]
	curFileId, err := strconv.Atoi(curFileName)
	if err != nil {
		err = fmt.Errorf("%s-Convert newFileName:%s to int failed:%s", prefix, curFileName, err)
		logUtil.ErrorLog(err.Error())
		panic(err)
	}

	newFileId := curFileId + 1
	newFileName := fmt.Sprintf("%08d", newFileId)

	// 加上文件后缀
	newFileName = fmt.Sprintf("%s.%s", newFileName, con_FileName_Suffix)

	return newFileName
}

// 获取文件夹下所有的sql文件
// dirPath:指定要获取的文件夹路径
// 返回值:
// []string:sql文件列表
func GetDataFileList(dirPath string) []string {
	// 获取当前目录中所有的数据文件列表
	fileList, err := fileUtil.GetFileList2(dirPath, "", con_FileName_Suffix)
	if err != nil {
		if os.IsNotExist(err) {
		} else {
			err = fmt.Errorf("%s/*.%s-Get file list failed:%s", dirPath, con_FileName_Suffix, err)
			logUtil.ErrorLog(err.Error())
			panic(err)
		}
	}

	// 如果文件数量大于1，则进行排序，以便于后续处理
	if len(fileList) > 1 {
		sort.Strings(fileList)
	}

	return fileList
}
