package main

import (
	"image"
	"image/color"
	"image/draw"

	"github.com/disintegration/gift"
	"golang.org/x/image/font"
	"golang.org/x/image/font/basicfont"
	"golang.org/x/image/math/fixed"

	"streamdeck-lets-go/internal/config"
)

func RenderKeyToImage(k *config.KeyConfig, keySize int, showLabelBackground bool) image.Image {
	if k == nil {
		return blankImage(keySize, color.RGBA{0, 0, 0, 255})
	}
	if k.Icon == "" && k.Label == "" {
		if k.Background != "" {
			if bg, err := parseHexColor(k.Background); err == nil {
				return blankImage(keySize, bg)
			}
		}
		return blankImage(keySize, color.RGBA{64, 64, 64, 255})
	}

	faScale := 0.55
	if k.IconScale != nil {
		faScale = *k.IconScale
	}

	if k.Icon != "" {
		img, err := loadImage(k.Icon, keySize, faScale)
		if err != nil {
			img = blankImage(keySize, color.RGBA{64, 64, 64, 255})
		}
		if k.Background != "" {
			if bg, err := parseHexColor(k.Background); err == nil {
				img = applyBackground(img, bg)
			}
		}
		if k.Label != "" {
			fontSize := 10.0
			if k.FontSize != nil {
				fontSize = *k.FontSize
			}
			return composeImageWithLabel(img, k.Label, keySize, fontSize, showLabelBackground)
		}
		g := gift.New(gift.Resize(keySize, keySize, gift.LanczosResampling))
		rgba := image.NewRGBA(image.Rect(0, 0, keySize, keySize))
		g.Draw(rgba, img)
		return rgba
	}

	if k.Background != "" {
		if bg, err := parseHexColor(k.Background); err == nil {
			if k.Label != "" {
				fontSize := 12.0
				if k.FontSize != nil {
					fontSize = *k.FontSize
				}
				return renderUnicodeText(k.Label, fontSize, keySize, bg, color.White)
			}
			return blankImage(keySize, bg)
		}
	}
	fontSize := 12.0
	if k.FontSize != nil {
		fontSize = *k.FontSize
	}
	return renderTextImage(k.Label, keySize, fontSize)
}

func blankImage(size int, c color.Color) image.Image {
	img := image.NewRGBA(image.Rect(0, 0, size, size))
	draw.Draw(img, img.Bounds(), &image.Uniform{c}, image.Point{}, draw.Src)
	return img
}

func composeImageWithLabel(src image.Image, text string, keySize int, fontSize float64, showLabelBackground bool) image.Image {
	g := gift.New(gift.Resize(keySize, keySize, gift.LanczosResampling))
	rgba := image.NewRGBA(image.Rect(0, 0, keySize, keySize))
	g.Draw(rgba, src)

	barHeight := 20
	if keySize < 72 {
		barHeight = 18
	}
	barRect := image.Rect(0, keySize-barHeight, keySize, keySize)
	if showLabelBackground {
		draw.Draw(rgba, barRect, &image.Uniform{color.RGBA{0, 0, 0, 180}}, image.Point{}, draw.Over)
	}

	if text != "" {
		face, err := parseDisplayFace(fontSize)
		if err != nil {
			face = basicfont.Face7x13
		} else {
			defer face.Close()
		}
		textW := font.MeasureString(face, text).Ceil()
		posX := (keySize - textW) / 2
		if posX < 2 {
			posX = 2
		}
		posY := keySize - barHeight/2 + face.Metrics().Height.Ceil()/2
		if posY >= keySize {
			posY = keySize - 2
		}

		d := &font.Drawer{
			Dst:  rgba,
			Src:  image.NewUniform(color.White),
			Face: face,
			Dot:  fixed.P(posX, posY),
		}
		d.DrawString(text)
	}

	return rgba
}

func renderTextImage(text string, keySize int, fontSize float64) image.Image {
	rgba := blankImage(keySize, color.RGBA{0, 0, 0, 0}).(*image.RGBA)

	if text != "" {
		face, err := parseDisplayFace(fontSize)
		if err != nil {
			face = basicfont.Face7x13
		} else {
			defer face.Close()
		}
		textW := font.MeasureString(face, text).Ceil()
		posX := (keySize - textW) / 2
		if posX < 2 {
			posX = 2
		}
		posY := keySize/2 + face.Metrics().Height.Ceil()/2

		d := &font.Drawer{
			Dst:  rgba,
			Src:  image.NewUniform(color.White),
			Face: face,
			Dot:  fixed.P(posX, posY),
		}
		d.DrawString(text)
	}

	return rgba
}
