package logic

import (
	"crypto/sha256"
	"encoding/hex"
	"io"
	"log"
	"mime/multipart"
	"path/filepath"
	"strings"

	"bsm/full/module/base/fts/internal/config"
	"bsm/full/module/base/fts/internal/impl"
	"bsm/full/module/base/fts/internal/models"
	"git.apinb.com/bsm-sdk/core/errcode"
	"git.apinb.com/bsm-sdk/core/infra"
	"git.apinb.com/bsm-sdk/core/middleware"
	"git.apinb.com/bsm-sdk/core/types"
	"git.apinb.com/bsm-sdk/core/utils"
	"github.com/gin-gonic/gin"
)

// Handler 上传文件
func Handler(c *gin.Context) {
	var (
		provider = strings.ToLower(c.PostForm("provider"))
		bucket   = strings.ToLower(c.PostForm("bucket"))
		claims   *types.JwtClaims
		err      error
	)

	claims, err = middleware.ParseAuth(c)
	if err != nil {
		log.Printf("获取当前登录用户信息失败: %v\n", err)
		infra.Response.Error(c, err)
		return
	}

	if provider == "" || bucket == "" {
		infra.Response.Error(c, errcode.NewError(400, "参数错误"))
		return
	}
	// if !strings.Contains(provider, "local") {
	// 	log.Println("provider参数错误")
	// 	infra.Response.Error(c, errcode.NewError(400, "provider参数错误"))
	// 	return
	// }

	fh, err := c.FormFile(config.Spec.FtsConfig.InputKey)
	if err != nil {
		infra.Response.Error(c, err)
		return
	}

	// 获取文件信息
	fileSize := fh.Size
	if fileSize > config.Spec.FtsConfig.MaxSize {
		infra.Response.Error(c, errcode.NewError(400, "文件大小超过限制"))
		return
	}

	// 检测是否是允许上传的文件类型
	fileExt := filepath.Ext(fh.Filename)
	if !isAllow(fileExt) {
		log.Println("不允许上传的文件类型:", fileExt)
		infra.Response.Error(c, errcode.NewError(501, "不允许上传的文件类型"))
		return
	}

	fileHash, err := chksum(fh)
	if err != nil {
		log.Println("文件校验失败:", err)
		infra.Response.Error(c, err)
		return
	}

	record := models.FtsRecord{
		Identity:      utils.UUID(),
		OwnerID:       claims.ID,
		OwnerIdentity: claims.Identity,
		Name:          fh.Filename,
		Ext:           fileExt,
		Size:          uint64(fileSize),
		Hash:          fileHash,
		Status:        0,
	}

	switch provider {
	case "local":
		err = LocalUpload(fh, &record, c, bucket)
	case "minio":
		err = OssUpload(fh, &record, c, bucket)
	default:
		infra.Response.Error(c, errcode.NewError(400, "provider参数错误"))
		return
	}
	if err != nil {
		infra.Response.Error(c, err)
		return
	}
	if err := impl.DBService.Create(&record).Error; err != nil {
		infra.Response.Error(c, err)
		return
	}

	infra.Response.Success(c, record)
}

func chksum(fh *multipart.FileHeader) (string, error) {
	// 2. 打开文件读取内容
	file, err := fh.Open()
	if err != nil {
		log.Println("multipart err:", err)
		return "", err
	}
	defer file.Close()

	// 3. 计算文件哈希值（sha256）
	hash := sha256.New()
	if _, err = io.Copy(hash, file); err != nil {
		log.Println("哈希计算失败:", err)
		return "", err
	}
	return hex.EncodeToString(hash.Sum(nil)), nil
}

func isAllow(extName string) bool {
	for _, allowExt := range config.Spec.FtsConfig.Allows {
		if extName == allowExt {
			return true
		}
	}
	return false
}
