package example

import (
	"io"
	"strconv"
	"strings"

	"kra/internal/biz/example"
	"kra/pkg/response"
	"kra/pkg/utils"

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

// BreakpointContinue
// @Tags      ExaFileUploadAndDownload
// @Summary   断点续传到服务器
// @Security  ApiKeyAuth
// @accept    multipart/form-data
// @Produce   application/json
// @Param     file  formData  file                           true  "断点续传示例"
// @Success   200   {object}  response.Response{msg=string}  "断点续传到服务器"
// @Router    /fileUploadAndDownload/breakpointContinue [post]
func (f *FileUploadApi) BreakpointContinue(c *gin.Context) {
	fileMd5 := c.Request.FormValue("fileMd5")
	fileName := c.Request.FormValue("fileName")
	chunkMd5 := c.Request.FormValue("chunkMd5")
	chunkNumber, _ := strconv.Atoi(c.Request.FormValue("chunkNumber"))
	chunkTotal, _ := strconv.Atoi(c.Request.FormValue("chunkTotal"))

	_, FileHeader, err := c.Request.FormFile("file")
	if err != nil {
		response.FailWithMessage("接收文件失败", c)
		return
	}

	file, err := FileHeader.Open()
	if err != nil {
		response.FailWithMessage("文件读取失败", c)
		return
	}
	defer file.Close()

	content, _ := io.ReadAll(file)
	if !utils.CheckMd5(content, chunkMd5) {
		response.FailWithMessage("检查md5失败", c)
		return
	}

	exaFile, err := breakpointContinueUsecase.FindOrCreateFile(c.Request.Context(), fileMd5, fileName, chunkTotal)
	if err != nil {
		response.FailWithMessage("查找或创建记录失败: "+err.Error(), c)
		return
	}

	pathC, err := utils.BreakPointContinue(content, fileName, chunkNumber, chunkTotal, fileMd5)
	if err != nil {
		response.FailWithMessage("断点续传失败: "+err.Error(), c)
		return
	}

	if err = breakpointContinueUsecase.CreateFileChunk(c.Request.Context(), exaFile.ID, pathC, chunkNumber); err != nil {
		response.FailWithMessage("创建文件记录失败: "+err.Error(), c)
		return
	}

	response.OkWithMessage("切片创建成功", c)
}

// FindFile
// @Tags      ExaFileUploadAndDownload
// @Summary   查找文件
// @Security  ApiKeyAuth
// @accept    multipart/form-data
// @Produce   application/json
// @Param     fileMd5     query     string                                                     true  "文件MD5"
// @Param     fileName    query     string                                                     true  "文件名"
// @Param     chunkTotal  query     int                                                        true  "切片总数"
// @Success   200         {object}  response.Response{data=map[string]interface{},msg=string}  "查找文件,返回包括文件详情"
// @Router    /fileUploadAndDownload/findFile [get]
func (f *FileUploadApi) FindFile(c *gin.Context) {
	fileMd5 := c.Query("fileMd5")
	fileName := c.Query("fileName")
	chunkTotal, _ := strconv.Atoi(c.Query("chunkTotal"))

	file, err := breakpointContinueUsecase.FindOrCreateFile(c.Request.Context(), fileMd5, fileName, chunkTotal)
	if err != nil {
		response.FailWithMessage("查找失败: "+err.Error(), c)
		return
	}

	response.OkWithDetailed(gin.H{"file": toFileResponse(file)}, "查找成功", c)
}

// BreakpointContinueFinish
// @Tags      ExaFileUploadAndDownload
// @Summary   创建文件
// @Security  ApiKeyAuth
// @accept    multipart/form-data
// @Produce   application/json
// @Param     fileMd5   query     string                                                     true  "文件MD5"
// @Param     fileName  query     string                                                     true  "文件名"
// @Success   200       {object}  response.Response{data=map[string]interface{},msg=string}  "创建文件,返回包括文件路径"
// @Router    /fileUploadAndDownload/findFile [post]
func (f *FileUploadApi) BreakpointContinueFinish(c *gin.Context) {
	fileMd5 := c.Query("fileMd5")
	fileName := c.Query("fileName")

	filePath, err := utils.MakeFile(fileName, fileMd5)
	if err != nil {
		response.FailWithDetailed(gin.H{"filePath": filePath}, "文件创建失败", c)
		return
	}

	response.OkWithDetailed(gin.H{"filePath": filePath}, "文件创建成功", c)
}

// RemoveChunk
// @Tags      ExaFileUploadAndDownload
// @Summary   删除切片
// @Security  ApiKeyAuth
// @accept    application/json
// @Produce   application/json
// @Param     data  body      map[string]string              true  "删除缓存切片"
// @Success   200   {object}  response.Response{msg=string}  "删除切片"
// @Router    /fileUploadAndDownload/removeChunk [post]
func (f *FileUploadApi) RemoveChunk(c *gin.Context) {
	var req struct {
		FileMd5  string `json:"fileMd5"`
		FilePath string `json:"filePath"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	// 路径穿越拦截
	if strings.Contains(req.FilePath, "..") || strings.Contains(req.FilePath, "../") ||
		strings.Contains(req.FilePath, "./") || strings.Contains(req.FilePath, ".\\") {
		response.FailWithMessage("非法路径，禁止删除", c)
		return
	}

	if err := utils.RemoveChunk(req.FileMd5); err != nil {
		response.FailWithMessage("缓存切片删除失败: "+err.Error(), c)
		return
	}

	if err := breakpointContinueUsecase.DeleteFileChunk(c.Request.Context(), req.FileMd5, req.FilePath); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	response.OkWithMessage("缓存切片删除成功", c)
}

func toFileResponse(file *example.ExaFile) map[string]interface{} {
	chunks := make([]map[string]interface{}, len(file.ExaFileChunk))
	for i, chunk := range file.ExaFileChunk {
		chunks[i] = map[string]interface{}{
			"ID":              chunk.ID,
			"exaFileID":       chunk.ExaFileID,
			"fileChunkNumber": chunk.FileChunkNumber,
			"fileChunkPath":   chunk.FileChunkPath,
		}
	}
	return map[string]interface{}{
		"ID":           file.ID,
		"fileName":     file.FileName,
		"fileMd5":      file.FileMd5,
		"filePath":     file.FilePath,
		"chunkTotal":   file.ChunkTotal,
		"isFinish":     file.IsFinish,
		"exaFileChunk": chunks,
	}
}
