package imgutils

import (
	"bytes"
	"encoding/base64"
	"github.com/golang/freetype"
	"github.com/golang/freetype/truetype"
	"github.com/nfnt/resize"
	"golang.org/x/image/font"
	"image"
	"image/color"
	"image/draw"
	_ "image/gif"
	"image/jpeg"
	_ "image/jpeg"
	_ "image/png"
	"io"
	"net/http"
)

// GetFromBase64 base64->image.image
func GetFromBase64(base64Img string) (image.Image, error) {
	empty := image.NewRGBA(image.Rectangle{
		Min: image.Point{},
		Max: image.Point{},
	})
	if len(base64Img) == 0 {
		return empty, nil
	}

	imgBytes, err := base64.StdEncoding.DecodeString(base64Img)
	if err != nil {
		return empty, err
	}

	img, _, err := image.Decode(bytes.NewBuffer(imgBytes))
	if err != nil {
		return empty, err
	}

	return img, nil
}

// GetFromBytes bytes->image.image
func GetFromBytes(imgBytes []byte) (image.Image, error) {
	empty := image.NewRGBA(image.Rectangle{
		Min: image.Point{},
		Max: image.Point{},
	})
	if len(imgBytes) == 0 {
		return empty, nil
	}

	img, _, err := image.Decode(bytes.NewBuffer(imgBytes))
	if err != nil {
		return empty, err
	}

	return img, nil
}

// ResizeImg 缩放原始图片 只给width,height,按比例缩放
func Resize(src image.Image, width, height uint) image.Image {
	return resize.Resize(width, height, src, resize.Lanczos3)
}

func TransBackground(src image.Image) image.Image {
	newRgba := image.NewRGBA(src.Bounds())
	for i := 0; i < src.Bounds().Dx(); i++ {
		for j := 0; j < src.Bounds().Dy(); j++ {
			colorRgb := src.At(i, j)
			r, g, b, a := colorRgb.RGBA()
			nR := uint16(r)
			nG := uint16(g)
			nB := uint16(b)
			nA := uint16(a)
			if nA == 0 {
				nR = 65535
				nG = 65535
				nB = 65535
				nA = 65535
			}
			newRgba.Set(i, j, color.RGBA64{R: nR, G: nG, B: nB, A: nA})
		}
	}
	return newRgba
}

// 圆形遮罩结构 实现 image.image
type circle struct {
	// 圆心位置
	p image.Point

	// 半径
	r int
}

func (c *circle) ColorModel() color.Model {
	return color.AlphaModel
}

func (c *circle) Bounds() image.Rectangle {
	return image.Rect(c.p.X-c.r, c.p.Y-c.r, c.p.X+c.r, c.p.Y+c.r)
}

func (c *circle) At(x, y int) color.Color {
	xx, yy, rr := float64(x-c.p.X)+0.5, float64(y-c.p.Y)+0.5, float64(c.r)
	if xx*xx+yy*yy < rr*rr {
		return color.Alpha{A: 255} // 半径以内的图案设成完全不透明
	}
	return color.Alpha{}
}

// CircleMask 从图片中间取圆形遮罩
func CircleMask(src image.Image) image.Image {
	c := circle{
		p: src.Bounds().Max.Div(2),
		r: src.Bounds().Dx() / 2,
	}

	circleImg := image.NewRGBA(image.Rect(0, 0, src.Bounds().Dx(), src.Bounds().Dy()))
	draw.DrawMask(circleImg, circleImg.Bounds(), src, image.Point{}, &c, image.Point{}, draw.Over)

	return circleImg
}

// MiddleCoverCoordinate 中间覆盖图片到背景图片坐标计算
func MiddleCoverCoordinate(background image.Image, coverImg image.Image) image.Rectangle {
	minPoint := background.Bounds().Max.Div(2).Sub(coverImg.Bounds().Max.Div(2))
	maxPoint := minPoint.Add(coverImg.Bounds().Max)

	return image.Rectangle{
		Min: minPoint,
		Max: maxPoint,
	}
}

// RGBA RGBA
func RGBA(img image.Image) *image.RGBA {
	baseSrcBounds := img.Bounds().Max

	newWidth := baseSrcBounds.X
	newHeight := baseSrcBounds.Y

	// 底板
	des := image.NewRGBA(image.Rect(0, 0, newWidth, newHeight))

	//首先将一个图片信息存入jpg
	draw.Draw(des, des.Bounds(), img, img.Bounds().Min, draw.Over)

	return des
}

// DrawTextInfo 图片绘字信息
type DrawTextInfo struct {
	Text string
	X    int
	Y    int
}

// TextBrush 字体相关
type TextBrush struct {
	FontType  *truetype.Font
	FontSize  float64
	FontColor *image.Uniform
	TextWidth int
	DrawInfo  *DrawTextInfo
}

func NewTextBrush(font *truetype.Font, FontSize float64, FontColor *image.Uniform, textWidth int, drawInfo *DrawTextInfo) (*TextBrush, error) {
	if textWidth <= 0 {
		textWidth = 20
	}

	return &TextBrush{FontType: font, FontSize: FontSize, FontColor: FontColor, TextWidth: textWidth, DrawInfo: drawInfo}, nil
}

func (tb *TextBrush) DrawFontOnRGBA(rgba *image.RGBA) error {
	c := freetype.NewContext()
	c.SetDPI(72)
	c.SetFont(tb.FontType)
	c.SetHinting(font.HintingFull)
	c.SetFontSize(tb.FontSize)
	c.SetClip(rgba.Bounds())
	c.SetDst(rgba)
	c.SetSrc(tb.FontColor)

	_, err := c.DrawString(tb.DrawInfo.Text, freetype.Pt(tb.DrawInfo.X, tb.DrawInfo.Y))
	if err != nil {
		return err
	}

	return nil
}

func DrawStringAndSave(img image.Image, infos []*TextBrush) (image.Image, error) {
	// 创建画板
	desImg := RGBA(img)
	for _, brush := range infos {
		err := brush.DrawFontOnRGBA(desImg)
		if err != nil {
			return nil, err
		}
	}

	return desImg, nil
}

func CreateWhiteBackground(w int, h int) *image.RGBA {
	newRgba := image.NewRGBA(image.Rectangle{
		Min: image.Point{},
		Max: image.Point{X: w, Y: h},
	})

	for i := 0; i < newRgba.Bounds().Dx(); i++ {
		for j := 0; j < newRgba.Bounds().Dy(); j++ {
			colorRgb := newRgba.At(i, j)
			r, g, b, a := colorRgb.RGBA()
			nR := uint16(r)
			nG := uint16(g)
			nB := uint16(b)
			nA := uint16(a)
			if nA == 0 {
				nR = 65535
				nG = 65535
				nB = 65535
				nA = 65535
			}
			newRgba.Set(i, j, color.RGBA64{R: nR, G: nG, B: nB, A: nA})
		}
	}

	return newRgba
}

func MergeImagesHighLow(highImg image.Image, lowImg image.Image) image.Image {
	var x, y int

	if highImg.Bounds().Dx() >= lowImg.Bounds().Dx() {
		x = highImg.Bounds().Dx()
	} else {
		x = lowImg.Bounds().Dx()
	}

	y = highImg.Bounds().Dy() + lowImg.Bounds().Dy()
	destDraw := CreateWhiteBackground(x, y)

	// 先画风景图
	draw.Draw(destDraw, destDraw.Bounds(), highImg, highImg.Bounds().Min, draw.Over)

	// 画微信图
	draw.Draw(destDraw, image.Rectangle{
		Min: image.Point{Y: highImg.Bounds().Max.Y},
		Max: destDraw.Bounds().Max,
	}, lowImg, lowImg.Bounds().Min, draw.Over)

	return destDraw
}

func GetBase64FromUrl(url string) (string, error) {
	res, err := http.Get(url)
	if err != nil {
		return "", err
	}

	defer func(Body io.ReadCloser) {
		err := Body.Close()
		if err != nil {

		}
	}(res.Body)

	data, err := io.ReadAll(res.Body)
	if err != nil {
		return "", err
	}

	return base64.StdEncoding.EncodeToString(data), nil
}

func ReplaceWechatMiniProgramQrLogo(qr image.Image, logo image.Image) ([]byte, error) {
	logoSize := qr.Bounds().Dx() / 3
	resizeLogo := resize.Resize(uint(logoSize), uint(logoSize), logo, resize.Bilinear)

	// 计算放置图像的位置
	posX := (qr.Bounds().Dx() - resizeLogo.Bounds().Dx()) / 2
	posY := (qr.Bounds().Dy() - resizeLogo.Bounds().Dy()) / 2

	bg := image.NewRGBA(image.Rect(0, 0, 150, 148))

	// 将每个像素设置为白色
	for x := 0; x < 150; x++ {
		for y := 0; y < 148; y++ {
			bg.Set(x, y, color.White)
		}
	}

	b := qr.Bounds()
	m := image.NewRGBA(b)
	draw.Draw(m, b, qr, image.Point{}, draw.Src)
	draw.Draw(m, bg.Bounds().Add(image.Point{X: 140, Y: 141}), bg, image.Point{}, draw.Src)
	draw.Draw(m, resizeLogo.Bounds().Add(image.Point{X: posX, Y: posY}),
		resizeLogo, image.Point{}, draw.Over)

	var bs bytes.Buffer
	err := jpeg.Encode(&bs, m, &jpeg.Options{Quality: jpeg.DefaultQuality})
	if err != nil {
		return nil, err
	}

	return bs.Bytes(), nil
}