package file

import (
	"fmt"
	"io"
	"mime/multipart"
	"os"
	"path/filepath"
	"sort"
	"strconv"

	"be.ems/src/framework/logger"
)

// transferToNewFile 读取目标文件转移到新路径下
//
// readFilePath 读取目标文件
//
// writePath 写入路径
//
// fileName 文件名称
func transferToNewFile(file *multipart.FileHeader, dst string) error {
	src, err := file.Open()
	if err != nil {
		return err
	}
	defer src.Close()

	if err = os.MkdirAll(filepath.Dir(dst), 0775); err != nil {
		return err
	}

	out, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer out.Close()

	_, err = io.Copy(out, src)
	return err
}

// mergeToNewFile 将多个文件合并成一个文件并删除合并前的切片目录文件
//
// dirPath 读取要合并文件的目录
//
// writePath 写入路径
//
// fileName 文件名称
func mergeToNewFile(dirPath string, writePath string, fileName string) error {
	// 读取目录下所有文件并排序，注意文件名称是否数值
	fileNameList, err := getDirFileNameList(dirPath)
	if err != nil {
		return fmt.Errorf("failed to read merge target file: %v", err)
	}
	if len(fileNameList) <= 0 {
		return fmt.Errorf("failed to read merge target file")
	}

	// 排序
	sort.Slice(fileNameList, func(i, j int) bool {
		numI, _ := strconv.Atoi(fileNameList[i])
		numJ, _ := strconv.Atoi(fileNameList[j])
		return numI < numJ
	})

	// 写入到新路径文件
	newFilePath := filepath.Join(writePath, fileName)
	if err = os.MkdirAll(filepath.Dir(newFilePath), 0775); err != nil {
		return err
	}

	// 转移完成后删除切片目录
	defer os.Remove(dirPath)

	// 打开新路径文件
	outputFile, err := os.Create(newFilePath)
	if err != nil {
		return fmt.Errorf("failed to create file: %v", err)
	}
	defer outputFile.Close()

	// 逐个读取文件后进行流拷贝数据块
	for _, fileName := range fileNameList {
		chunkPath := filepath.Join(dirPath, fileName)
		// 拷贝结束后删除切片
		defer os.Remove(chunkPath)
		// 打开切片文件
		inputFile, err := os.Open(chunkPath)
		if err != nil {
			return fmt.Errorf("failed to open file: %v", err)
		}
		defer inputFile.Close()
		// 拷贝文件流
		_, err = io.Copy(outputFile, inputFile)
		if err != nil {
			return fmt.Errorf("failed to copy file data: %w", err)
		}
	}

	return nil
}

// getFileSize 读取文件大小
func getFileSize(filePath string) int64 {
	// 获取文件信息
	fileInfo, err := os.Stat(filePath)
	if err != nil {
		logger.Errorf("Failed stat %s: %v", filePath, err)
		return 0
	}
	// 获取文件大小（字节数）
	return fileInfo.Size()
}

// 读取文件流用于返回下载
//
// filePath 文件路径
// startOffset, endOffset 分片块读取区间，根据文件切片的块范围
func getFileStream(filePath string, startOffset, endOffset int64) ([]byte, error) {
	// 打开文件
	file, err := os.Open(filePath)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	// 获取文件的大小
	fileInfo, err := file.Stat()
	if err != nil {
		return nil, err
	}
	fileSize := fileInfo.Size()

	// 确保起始和结束偏移量在文件范围内
	if startOffset > fileSize {
		startOffset = 0
	}
	if endOffset >= fileSize {
		endOffset = fileSize - 1
	}

	// 计算切片的大小
	chunkSize := endOffset - startOffset + 1

	// 创建 SectionReader
	reader := io.NewSectionReader(file, startOffset, chunkSize)

	// 创建一个缓冲区来存储读取的数据
	buffer := make([]byte, chunkSize)

	// 读取数据到缓冲区
	_, err = reader.Read(buffer)
	if err != nil && err != io.EOF {
		return nil, err
	}

	return buffer, nil
}

// 获取文件目录下所有文件名称，不含目录名称
//
// filePath 文件路径
func getDirFileNameList(dirPath string) ([]string, error) {
	fileNames := []string{}

	dir, err := os.Open(dirPath)
	if err != nil {
		return fileNames, nil
	}
	defer dir.Close()

	fileInfos, err := dir.Readdir(-1)
	if err != nil {
		return fileNames, err
	}

	for _, fileInfo := range fileInfos {
		if fileInfo.Mode().IsRegular() {
			fileNames = append(fileNames, fileInfo.Name())
		}
	}

	return fileNames, nil
}
