package commonController

import (
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"x_admin/core/response"
	"x_admin/service/commonService"

	"github.com/gin-gonic/gin"
)

func UploadChunkRoute(rg *gin.RouterGroup) {
	handle := uploadChunkHandler{
		uploadPath: "./uploads",
		tmpPath:    "./uploads/.tmp",
	}
	os.MkdirAll(handle.uploadPath, 0755)
	os.MkdirAll(handle.tmpPath, 0755)

	rg = rg.Group("/common")
	rg.GET("/uploadChunk/CheckFileExist", handle.CheckFileExist)
	// rg.GET("/uploadChunk/CheckChunkExist", handle.CheckChunkExist)
	rg.GET("/uploadChunk/HasChunk", handle.HasChunk)

	rg.POST("/uploadChunk/UploadChunk", handle.UploadChunk)
	rg.POST("/uploadChunk/MergeChunk", handle.MergeChunk)
}

type uploadChunkHandler struct {
	uploadPath string
	tmpPath    string
}

func (uh uploadChunkHandler) getFilePath(fileMd5 string, fileName string) string {
	// 获取文件后缀
	ext := filepath.Ext(fileName)

	return fmt.Sprintf("%s/%s%s", uh.uploadPath, fileMd5, ext)
}
func (uh uploadChunkHandler) getChunkDir(fileMd5 string, chunkSize string) string {
	return fmt.Sprintf("%s/%s_%s", uh.tmpPath, fileMd5, chunkSize)
}
func (uh uploadChunkHandler) getChunkPath(fileMd5 string, chunkSize string, index string) string {
	return fmt.Sprintf("%s/%s_%s/%s", uh.tmpPath, fileMd5, chunkSize, index)
}

func (uh uploadChunkHandler) CheckFileExist(c *gin.Context) {
	var fileMd5 = c.Query("fileMd5")
	var fileName = c.Query("fileName")
	if fileMd5 == "" {
		response.FailWithMsg(c, response.SystemError, "文件hash错误")
		return
	}
	if fileName == "" {
		response.FailWithMsg(c, response.SystemError, "文件名错误")
		return
	}
	//文件类型白名单
	var whiteList = []string{
		".jpg",
		".jpeg",
		".png",
		".gif",
		".bmp",
		".svg",
		".webp",
		".avif",
		".txt",
		".mp4",
		".avi",
		".mov",
		".wmv",
		".flv",
		".mkv",
		".mp3",
		".wav",
		".aac",
		".flac",
		".ogg",
		".m4a",
		".pdf",
		".doc",
		".docx",
		".xls",
		".xlsx",
		".ppt",
		".pptx",
		".zip",
		".rar",
		".7z",
		".tar",
		".gz",
		".bz2",
		".xz",
		".msi",
		".exe",
		".dmg",
		".iso",
		".app",
		".deb",
		".rpm",
		".pkg",
		".apk",
	}
	var fileExt = ""
	for _, ext := range whiteList {
		if strings.HasSuffix(fileName, ext) {
			fileExt = ext
			break
		}
	}
	if fileExt == "" {
		response.FailWithMsg(c, response.SystemError, "文件类型错误")
		return
	}

	// var fileName = url.QueryEscape(c.Query("fileName"))
	// 正则检查MD5
	reg := regexp.MustCompile(`^[a-zA-Z0-9_]+$`)
	if !reg.MatchString(fileMd5) {
		response.FailWithMsg(c, response.SystemError, "文件hash错误")
		return
	}
	var filePath = uh.getFilePath(fileMd5, fileName)
	// 检查文件是否存在
	if commonService.UploadChunkService.CheckFileExist(filePath) {
		response.OkWithData(c, filePath)
		return
	}
	response.OkWithData(c, nil)
}
func (uh uploadChunkHandler) HasChunk(c *gin.Context) {
	var fileMd5 = c.Query("fileMd5")
	var chunkSize = c.Query("chunkSize")
	if fileMd5 == "" {
		response.FailWithMsg(c, response.SystemError, "文件hash错误")
		return
	}
	if chunkSize == "" {
		response.FailWithMsg(c, response.SystemError, "分片大小错误")
		return
	}
	var chunkDir = uh.getChunkDir(fileMd5, chunkSize)
	var HasChunk = commonService.UploadChunkService.HasChunk(chunkDir)
	response.OkWithData(c, HasChunk)
}

// 检查chunk是否存在
// func (uh uploadChunkHandler) CheckChunkExist(c *gin.Context) {
// 	fileMd5 := c.Query("fileMd5") // 上传文件的md5
// 	chunkSize := c.Query("chunkSize")
// 	index := c.Query("index") // 分片序号
// 	// chunkPath := fmt.Sprintf("%s/%s/%s", uh.tmpPath, fileMd5, index)
// 	chunkPath := uh.getChunkPath(fileMd5, chunkSize, index)
// 	if commonService.UploadChunkService.CheckFileExist(chunkPath) {
// 		response.OkWithData(c, 1)
// 		return
// 	}
// 	response.OkWithData(c, 0)
// }

// UploadChunk 上传分片
func (uh uploadChunkHandler) UploadChunk(c *gin.Context) {
	chunk, _ := c.FormFile("chunk")      // 分片文件
	chunkSize := c.PostForm("chunkSize") // 分片分割的大小
	index := c.PostForm("index")         // 分片序号
	fileMd5 := c.PostForm("fileMd5")     // 上传文件的md5
	if fileMd5 == "" {
		response.FailWithMsg(c, response.SystemError, "文件hash错误")
		return
	}
	if chunkSize == "" {
		response.FailWithMsg(c, response.SystemError, "分片大小错误")
		return
	}
	if index == "" {
		response.FailWithMsg(c, response.SystemError, "分片序号错误")
		return
	}
	if chunk == nil {
		response.FailWithMsg(c, response.SystemError, "分片文件错误")
		return
	}

	chunkDir := uh.getChunkDir(fileMd5, chunkSize)
	chunkPath := uh.getChunkPath(fileMd5, chunkSize, index)
	err := commonService.UploadChunkService.UploadChunk(chunkDir, chunkPath, chunk)
	if err != nil {
		response.FailWithMsg(c, response.SystemError, err.Error())
		return
	}
	response.Ok(c)
}
func (uh uploadChunkHandler) MergeChunk(c *gin.Context) {
	var MergeChunk struct {
		FileMd5    string `json:"fileMd5"`    // 上传文件的md5
		FileName   string `json:"fileName"`   // 文件名
		ChunkCount int    `json:"chunkCount"` // 分片数量
		ChunkSize  int    `json:"chunkSize"`  // 分片分割的大小,作用：确保不同分片大小不放在同一目录
	}
	bindErr := c.ShouldBindJSON(&MergeChunk)
	if bindErr != nil {
		response.FailWithMsg(c, response.SystemError, bindErr.Error())
		return
	}
	if MergeChunk.FileMd5 == "" {
		response.FailWithMsg(c, response.SystemError, "文件hash错误")
		return
	}
	if MergeChunk.FileName == "" {
		response.FailWithMsg(c, response.SystemError, "文件名错误")
		return
	}
	if MergeChunk.ChunkCount <= 0 {
		response.FailWithMsg(c, response.SystemError, "分片数量错误")
		return
	}
	if MergeChunk.ChunkSize <= 0 {
		response.FailWithMsg(c, response.SystemError, "分片大小错误")
		return
	}
	var filePath = uh.getFilePath(MergeChunk.FileMd5, MergeChunk.FileName)
	var chunkDir = uh.getChunkDir(MergeChunk.FileMd5, fmt.Sprintf("%d", MergeChunk.ChunkSize))
	err := commonService.UploadChunkService.MergeChunk(chunkDir, filePath, MergeChunk.ChunkCount)
	if err != nil {
		response.FailWithMsg(c, response.SystemError, err.Error())
		return
	}
	response.OkWithData(c, filePath)
}
