package logic

import (
	"dubbo.apache.org/dubbo-go/v3/common/logger"
	"errors"
	"fmt"
	"fonchain-fiee/pkg/config"
	"fonchain-fiee/pkg/e"
	"github.com/fonchain_enterprise/utils/objstorage"
	"github.com/rwcarlsen/goexif/exif"
	"golang.org/x/image/bmp"
	"image"
	"image/jpeg"
	"image/png"
	"io/ioutil"
	"os"
	"path"
	"strings"
)

type IUpload interface{}

type Upload struct{}

// ReadOrientation 方向判断
func ReadOrientation(filename string) (direct int, err error) {
	file, err := os.Open(filename)
	defer file.Close()
	if err != nil {
		logger.Error("failed to open file, err: ", err)
		return
	}
	x, err := exif.Decode(file)
	if err != nil {
		logger.Error("failed to decode file, err: ", err)
		return
	}
	orientation, err := x.Get(exif.Orientation)
	if err != nil {
		logger.Error("failed to orientation file, err: ", err)
		return
	}
	direct, err = orientation.Int(0)
	if err != nil {
		logger.Error("failed to convert type file, err: ", err)
		return
	}
	return
}

// 旋转90度
func rotate90(m image.Image) image.Image {
	rotate90 := image.NewRGBA(image.Rect(0, 0, m.Bounds().Dy(), m.Bounds().Dx()))
	// 矩阵旋转
	for x := m.Bounds().Min.Y; x < m.Bounds().Max.Y; x++ {
		for y := m.Bounds().Max.X - 1; y >= m.Bounds().Min.X; y-- {
			//  设置像素点
			rotate90.Set(m.Bounds().Max.Y-x, y, m.At(y, x))
		}
	}
	return rotate90
}

// 旋转180度
func rotate180(m image.Image) image.Image {
	rotate180 := image.NewRGBA(image.Rect(0, 0, m.Bounds().Dx(), m.Bounds().Dy()))
	// 矩阵旋转
	for x := m.Bounds().Min.X; x < m.Bounds().Max.X; x++ {
		for y := m.Bounds().Min.Y; y < m.Bounds().Max.Y; y++ {
			//  设置像素点
			rotate180.Set(m.Bounds().Max.X-x, m.Bounds().Max.Y-y, m.At(x, y))
		}
	}
	return rotate180
}

// 旋转270度
func rotate270(m image.Image) image.Image {
	rotate270 := image.NewRGBA(image.Rect(0, 0, m.Bounds().Dy(), m.Bounds().Dx()))
	// 矩阵旋转
	for x := m.Bounds().Min.Y; x < m.Bounds().Max.Y; x++ {
		for y := m.Bounds().Max.X - 1; y >= m.Bounds().Min.X; y-- {
			// 设置像素点
			rotate270.Set(x, m.Bounds().Max.X-y, m.At(y, x))
		}
	}
	return rotate270
}

func MakeThumbnail(imagePath, savePath string) error {
	prefix := strings.ToLower(path.Ext("./2.jpg"))
	ori, err := ReadOrientation(imagePath)
	if err != nil {
		return err
	}
	file, _ := os.Open(imagePath)
	defer file.Close()
	img, _, err := image.Decode(file)
	if err != nil {
		return err
	}
	//苹果手机拍照的图片，会有方向属性Orientation，
	//经过Decode和Encode，编码处理后，方向属性会丢失，导致图片被旋转
	switch ori {
	case 6: //90度图片旋转
		img = rotate90(img)
	case 3:
		img = rotate180(img)
	case 8:
		img = rotate270(img)
	}
	newImg, _ := os.Create(savePath)
	defer newImg.Close()
	switch prefix {
	case ".jpg", ".jpeg":
		err = jpeg.Encode(newImg, img, &jpeg.Options{Quality: 100})
	case "png":
		err = png.Encode(newImg, img)
	case "bmp":
		err = bmp.Encode(newImg, img)
	default:
		err = jpeg.Encode(newImg, img, &jpeg.Options{Quality: 100})
	}
	if err != nil {
		logger.Error("Encode err", err)
		return err
	}
	return nil
}

func (u *Upload) PutBos(filePath string, mediaType string, needRemove bool) (url string, err error) {
	BOSClient, err := objstorage.NewOSS(config.ConfigData.Oss.AccessKeyId, config.ConfigData.Oss.AccessKeySecret, config.ConfigData.Oss.Endpoint)
	if err != nil {
		logger.Errorf("PutBos NewOOS err ", err)
		err = errors.New(e.GetMsg(e.ErrorUploadBos))
		return
	}
	f, err := os.Open(filePath)
	if err != nil {
		logger.Errorf("PutBos Open err %+v", err.Error())
		return
	}
	fileBytes, _ := ioutil.ReadAll(f)
	f.Close()
	//删除本地文件
	if needRemove {
		os.Remove(filePath)
	}
	filePath = strings.Replace(filePath, "./runtime", "", 1)
	var objectName string = fmt.Sprintf("%s/%s%s", config.ConfigData.Oss.BaseDir, config.Env, filePath)
	_, err = BOSClient.PutObjectFromBytes(config.ConfigData.Oss.BucketName, objectName, fileBytes)
	if err != nil {
		logger.Errorf("PutBos PutObject err %+v", err.Error())
		err = errors.New(e.GetMsg(e.ErrorUploadBos))
		return
	}
	//url = fmt.Sprintf("%s%s%s/%s", config.BosHttp, config.BosBucketName, config.BosUrl, objectName)
	url = fmt.Sprintf("%s/%s", config.ConfigData.Oss.CdnHost, objectName)
	return
}

func MakeThumbnailDefault270(imagePath, savePath string) error {
	prefix := strings.ToLower(path.Ext("./2.jpg"))

	file, _ := os.Open(imagePath)
	defer file.Close()
	img, _, err := image.Decode(file)
	if err != nil {
		return err
	}
	img = rotate270(img)

	newImg, _ := os.Create(savePath)
	defer newImg.Close()
	switch prefix {
	case ".jpg", ".jpeg":
		err = jpeg.Encode(newImg, img, &jpeg.Options{Quality: 100})
	case "png":
		err = png.Encode(newImg, img)
	case "bmp":
		err = bmp.Encode(newImg, img)
	default:
		err = jpeg.Encode(newImg, img, &jpeg.Options{Quality: 100})
	}
	if err != nil {
		logger.Error("Encode err", err)
		return err
	}
	return nil
}
