package igwrap

import (
	"sync"

	"edgaru089.ink/go/gl01/internal/util/itype"
	"github.com/inkyblackness/imgui-go/v4"
)

// Image creates a ImGUI image based on the given texture.
// For *render.Texture, use tex.Handle().
//
// size is in pixels. texRange is in [0, 1].
func Image(tex uint32, size itype.Vec2f, texRange itype.Rectf) {
	min, max := texRange.MinPoint(), texRange.MaxPoint()
	if GetTextureFlag(tex)&TextureFlag_FlipY == 0 {
		min[1], max[1] = max[1], min[1] // swap minY/maxY
	}
	imgui.ImageV(
		imgui.TextureID(tex),
		Vec2(size),
		Vec2(min), Vec2(max),
		Color(255, 255, 255, 255),
		imgui.Vec4{},
	)
}

// ImageV creates a ImGUI image based on the given texture.
// For *render.Texture, use tex.Handle().
//
// size is in pixels. texRange is in [0, 1].
func ImageV(tex uint32, size itype.Vec2f, texRange itype.Rectf, texColor itype.Vec4f, borderColor itype.Vec4f) {
	min, max := texRange.MinPoint(), texRange.MaxPoint()
	if GetTextureFlag(tex)&TextureFlag_FlipY == 0 {
		min[1], max[1] = max[1], min[1] // swap minY/maxY
	}
	imgui.ImageV(
		imgui.TextureID(tex),
		Vec2(size),
		Vec2(min), Vec2(max),
		Vec4(texColor),
		Vec4(borderColor),
	)
}

func ImageButton(tex uint32, size itype.Vec2f, texRange itype.Rectf) bool {
	min, max := texRange.MinPoint(), texRange.MaxPoint()
	if GetTextureFlag(tex)&TextureFlag_FlipY == 0 {
		min[1], max[1] = max[1], min[1] // swap minY/maxY
	}
	return imgui.ImageButtonV(
		imgui.TextureID(tex),
		Vec2(size),
		Vec2(min), Vec2(max),
		-1,
		imgui.Vec4{},
		imgui.Vec4{1, 1, 1, 1},
	)
}

func ImageButtonV(tex uint32, size itype.Vec2f, texRange itype.Rectf, padding int, bgCol, tintCol itype.Vec4f) bool {
	min, max := texRange.MinPoint(), texRange.MaxPoint()
	if GetTextureFlag(tex)&TextureFlag_FlipY == 0 {
		min[1], max[1] = max[1], min[1] // swap minY/maxY
	}
	return imgui.ImageButtonV(
		imgui.TextureID(tex),
		Vec2(size),
		Vec2(min), Vec2(max),
		padding,
		Vec4(bgCol),
		Vec4(tintCol),
	)
}

// Per-texture flags. This is passed to the shader as-is.
//
// FilpY is handled by the ImageXXX() call.
type TextureFlag int

const (
	TextureFlag_Red   TextureFlag = 1 << iota // Renders the Red channel.
	TextureFlag_Green                         // Renders the Green channel.
	TextureFlag_Blue                          // Renders the Blue channel.
	TextureFlag_Alpha                         // Renders the Alpha channel.

	TextureFlag_Linear    // Linear source data, requires gamma correction.
	TextureFlag_ImGUIFont // This is a font texture from ImGUI, with a single red channel.
	TextureFlag_FlipY     // The render should flip the Y axis of the texture. By default ImageXXX()s render textures with (0,0) at the bottom left, and this is for in case you want to flip them.

	TextureFlag_RGB  = TextureFlag_Red | TextureFlag_Green | TextureFlag_Blue
	TextureFlag_RGBA = TextureFlag_Red | TextureFlag_Green | TextureFlag_Blue | TextureFlag_Alpha
)

var (
	texflags     map[uint32]TextureFlag = make(map[uint32]TextureFlag)
	texflagslock sync.RWMutex
)

// SetTextureFlag changes the flag of a texture to the given flags combined.
func SetTextureFlag(tex uint32, flags ...TextureFlag) {
	var f TextureFlag
	for _, f0 := range flags {
		f |= f0
	}

	texflagslock.Lock()
	defer texflagslock.Unlock()
	texflags[tex] = f
}

// AddTextureFlag adds the given flags to the texture.
func AddTextureFlag(tex uint32, flags ...TextureFlag) {
	var f TextureFlag
	for _, f0 := range flags {
		f |= f0
	}

	texflagslock.Lock()
	defer texflagslock.Unlock()
	texflags[tex] |= f
}

// TextureFlag returns the flags of a given texture.
func GetTextureFlag(tex uint32) TextureFlag {
	texflagslock.RLock()
	defer texflagslock.RUnlock()
	return texflags[tex]
}
