package img

import (
	"fmt"
	"image"
	"image/color"
	"image/draw"
	"image/jpeg"
	"image/png"
	"math"
	"math/rand"
	"os"
	"strconv"
	"strings"

	"apigo.cc/gojs"
	"apigo.cc/gojs/goja"
	"github.com/disintegration/imaging"
	"github.com/fogleman/gg"
	"golang.org/x/image/font"
)

type Graphics struct {
	// img       image.Image
	bgColor   string
	lastColor string
	lastFont  font.Face
	dc        *gg.Context // 高级绘图上下文
}

func init() {
	obj := map[string]any{
		"createImage": CreateImage,
		"loadImage":   LoadImage,
		"loadFont":    LoadFont,
		"listFont":    ListFont,
		"randColor":   RandColor,
		"lineCap":     lineCap,
		"lineJoin":    lineJoin,
		"fillRule":    fillRule,
	}
	gojs.Register("apigo.cc/gojs/img", gojs.Module{
		Object: gojs.ToMap(obj),
		TsCode: gojs.MakeTSCode(obj),
	})
}

// CreateImage 创建一个新的图像
func CreateImage(width, height int, c *string) *Graphics {
	img := image.NewRGBA(image.Rect(0, 0, width, height))
	dc := gg.NewContextForImage(img)
	g := &Graphics{
		// img: dc.Image(),
		dc: dc,
	}
	if c != nil {
		g.bgColor = *c
		g.SetColor(*c)
		g.dc.Clear()
	}
	return g
}

// LoadImage 从文件加载图像
func LoadImage(filePath string, vm *goja.Runtime) (*Graphics, error) {
	filePath = gojs.FixPath(vm, filePath)
	file, err := os.Open(filePath)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	img, _, err := image.Decode(file)
	if err != nil {
		return nil, err
	}

	return &Graphics{
		// img: img,
		dc: gg.NewContextForImage(img),
	}, nil
}

func (g *Graphics) Clear(x, y, width, height int) {
	if g.bgColor != "" {
		g.dc.DrawRectangle(float64(x), float64(y), float64(width), float64(height))
		g.dc.SetColor(hexToRGBA(g.bgColor))
		g.dc.Fill()
		return
	}
	if img, ok := g.dc.Image().(*image.RGBA); ok {
		transparent := image.NewUniform(color.RGBA{0, 0, 0, 0})
		draw.Draw(img, image.Rect(x, y, x+width, y+height), transparent, image.Point{}, draw.Src)
	}
}

// SubImage 提取指定区域的子图
func (g *Graphics) Sub(x, y, width, height int) *Graphics {
	// bounds := image.Rect(x, y, x+width, y+height)
	newImg := image.NewRGBA(image.Rect(0, 0, width, height))
	draw.Draw(newImg, newImg.Bounds(), g.dc.Image(), image.Pt(x, y), draw.Src)
	newDC := gg.NewContextForImage(newImg)
	return &Graphics{
		// img:       newDC.Image(),
		dc:        newDC,
		bgColor:   g.bgColor,
		lastColor: g.lastColor,
		lastFont:  g.lastFont,
	}
}

// Clone 创建图像的深拷贝
func (g *Graphics) Clone() *Graphics {
	bounds := g.dc.Image().Bounds()
	newImg := image.NewRGBA(bounds)
	draw.Draw(newImg, bounds, g.dc.Image(), bounds.Min, draw.Src)

	return &Graphics{
		// img: newImg,
		dc: gg.NewContextForImage(newImg),
	}
}

func (g *Graphics) SetColor(c string) {
	g.lastColor = c
	g.dc.SetColor(hexToRGBA(c))
}

// // Image 绘制图片（支持多种布局模式）
// func (g *Graphics) Image(src *Graphics, x, y, width, height int, mode string) {
// 	if src == nil {
// 		return
// 	}

// 	srcBounds := src.img.Bounds()
// 	srcW := srcBounds.Dx()
// 	srcH := srcBounds.Dy()

// 	// 计算目标尺寸
// 	targetW := width
// 	targetH := height

// 	// 根据不同模式计算实际绘制区域
// 	var drawW, drawH int
// 	switch mode {
// 	case scaleMode.Fill:
// 		drawW = targetW
// 		drawH = targetH
// 	case scaleMode.Contain:
// 		ratio := math.Min(float64(targetW)/float64(srcW), float64(targetH)/float64(srcH))
// 		drawW = int(float64(srcW) * ratio)
// 		drawH = int(float64(srcH) * ratio)
// 	case scaleMode.Cover:
// 		ratio := math.Max(float64(targetW)/float64(srcW), float64(targetH)/float64(srcH))
// 		drawW = int(float64(srcW) * ratio)
// 		drawH = int(float64(srcH) * ratio)
// 	}

// 	// 计算居中位置
// 	offsetX := (targetW - drawW) / 2
// 	offsetY := (targetH - drawH) / 2

// 	// 缩放图片
// 	scaled := imaging.Resize(src.img, drawW, drawH, imaging.Lanczos)

// 	// 绘制图片
// 	g.dc.DrawImage(scaled, x+offsetX, y+offsetY)
// 	g.img = g.dc.Image()
// }

// Put 简单的把图原样贴上去
func (g *Graphics) Put(src *Graphics, x, y int) {
	if src == nil || src.dc == nil {
		return
	}
	// 直接绘制源图像，不进行缩放
	g.dc.DrawImage(src.dc.Image(), x, y)
	// g.img = g.dc.Image() // 更新主图像
}

// PutTo 将原图整张贴进去，根据mode处理尺寸
func (g *Graphics) PutTo(src *Graphics, dx, dy, dw, dh int, sizeMode string) {
	// 调用完整功能函数，源区域是整个源图像
	srcBounds := src.dc.Image().Bounds()
	g.PutBy(src, srcBounds.Min.X, srcBounds.Min.Y, srcBounds.Dx(), srcBounds.Dy(), dx, dy, dw, dh, sizeMode)
}

// PutBy 完整的贴图功能
func (g *Graphics) PutBy(src *Graphics, sx, sy, sw, sh, dx, dy, dw, dh int, sizeMode string) {
	// 基础检查
	if src == nil || src.dc == nil || sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0 {
		return
	}

	// 1. 裁剪源图像到指定区域
	srcBounds := src.dc.Image().Bounds()
	cropX := max(sx, srcBounds.Min.X)
	cropY := max(sy, srcBounds.Min.Y)
	cropW := min(sw, srcBounds.Dx())
	cropH := min(sh, srcBounds.Dy())

	cropped := imaging.Crop(src.dc.Image(), image.Rect(cropX, cropY, cropX+cropW, cropY+cropH))

	// 2. 根据模式计算缩放尺寸
	var (
		drawW, drawH int
		ratio        float64
	)

	switch sizeMode {
	case "contain":
		ratio = math.Min(float64(dw)/float64(cropW), float64(dh)/float64(cropH))
		drawW = int(float64(cropW) * ratio)
		drawH = int(float64(cropH) * ratio)
	case "cover":
		ratio = math.Max(float64(dw)/float64(cropW), float64(dh)/float64(cropH))
		drawW = int(float64(cropW) * ratio)
		drawH = int(float64(cropH) * ratio)
	case "fill":
		drawW = dw
		drawH = dh
	}

	// 3. 居中偏移计算
	offsetX := (dw - drawW) / 2
	offsetY := (dh - drawH) / 2

	// 4. 缩放图像
	scaled := imaging.Resize(cropped, drawW, drawH, imaging.Lanczos)

	// 5. 绘制到目标位置
	g.dc.DrawImage(scaled, dx+offsetX, dy+offsetY)
	// g.img = g.dc.Image()
}

// FillAreaWithImage 用图像填充目标区域
func (g *Graphics) FillAreaWithImage(src *Graphics, x, y, width, height int) {
	if src == nil {
		return
	}

	srcBounds := src.dc.Image().Bounds()
	srcW := srcBounds.Dx()
	srcH := srcBounds.Dy()

	// 计算需要复制的次数
	cols := (width + srcW - 1) / srcW
	rows := (height + srcH - 1) / srcH

	for row := 0; row < rows; row++ {
		for col := 0; col < cols; col++ {
			px := x + col*srcW
			py := y + row*srcH
			g.dc.DrawImage(src.dc.Image(), px, py)
		}
	}
	// g.img = g.dc.Image()
}

// ExportImage 导出图像到文件
func (g *Graphics) ExportImage(filePath string, quality *int, vm *goja.Runtime) error {
	filePath = gojs.FixPath(vm, filePath)
	file, err := os.Create(filePath)
	if err != nil {
		return err
	}
	defer file.Close()

	switch {
	case strings.HasSuffix(strings.ToLower(filePath), ".png"):
		return png.Encode(file, g.dc.Image())
	case strings.HasSuffix(strings.ToLower(filePath), ".jpg"),
		strings.HasSuffix(strings.ToLower(filePath), ".jpeg"):
		q := 85 // 默认质量
		if quality != nil {
			q = *quality
			if q < 0 {
				q = 0
			} else if q > 100 {
				q = 100
			}
		}
		return jpeg.Encode(file, g.dc.Image(), &jpeg.Options{Quality: q})
	default:
		return fmt.Errorf("unsupported file format: %s", filePath)
	}
}

// GetImageData 获取图像原始数据
// func (g *Graphics) GetImageData() image.Image {
// 	return g.img
// }

// hexToRGBA 将多种格式的十六进制颜色字符串转换为 color.RGBA
// 支持格式: #RRGGBB, #RRGGBBAA, #RGB, #RGBA
func hexToRGBA(hex string) color.Color {
	// 去除开头的 # 号并转为大写
	hex = strings.ToUpper(strings.TrimPrefix(hex, "#"))

	// 验证合法字符
	for _, ch := range hex {
		if !((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F')) {
			return color.RGBA{}
		}
	}

	switch len(hex) {
	case 3:
		hex = fmt.Sprintf("%c%c%c%c%c%c", hex[0], hex[0], hex[1], hex[1], hex[2], hex[2])
	case 4:
		hex = fmt.Sprintf("%c%c%c%c%c%c%c%c", hex[0], hex[0], hex[1], hex[1], hex[2], hex[2], hex[3], hex[3])
	}

	switch len(hex) {
	case 6: // #RRGGBB
		return color.RGBA{R: parseHex(hex[0:2]), G: parseHex(hex[2:4]), B: parseHex(hex[4:6]), A: 255}
	case 8: // #RRGGBBAA
		return color.RGBA{R: parseHex(hex[0:2]), G: parseHex(hex[2:4]), B: parseHex(hex[4:6]), A: parseHex(hex[6:8])}
	}
	return color.RGBA{}
}

func parseHex(s string) uint8 {
	val, _ := strconv.ParseUint(s, 16, 8)
	return uint8(val)
}

// 辅助函数：生成对比色
func RandColor() string {
	r := uint8(rand.Intn(150) + 50)
	gr := uint8(rand.Intn(150) + 50)
	b := uint8(rand.Intn(150) + 50)
	a := uint8(rand.Intn(150) + 105)
	return fmt.Sprintf("#%02X%02X%02X%02X", r, gr, b, a)
}
