package d2helper

import (
	"image/color"
	"math"

	"github.com/hajimehoshi/ebiten"
)

type colorMCacheKey uint32

type colorMCacheEntry struct {
	m     ebiten.ColorM
	atime int64
}

var (
	colorMCache    = map[colorMCacheKey]*colorMCacheEntry{}
	emptyColorM    ebiten.ColorM
	monotonicClock int64
	cacheLimit     = 512
)

func init() {
	emptyColorM.Scale(0, 0, 0, 0)
}

func now() int64 {
	monotonicClock++
	return monotonicClock
}

// ColorToColorM converts a normal color to a color matrix
func ColorToColorM(clr color.Color) ebiten.ColorM {
	// RGBA() is in [0 - 0xffff]. Adjust them in [0 - 0xff].
	cr, cg, cb, ca := clr.RGBA()
	cr >>= 8
	cg >>= 8
	cb >>= 8
	ca >>= 8
	if ca == 0 {
		return emptyColorM
	}
	key := colorMCacheKey(uint32(cr) | (uint32(cg) << 8) | (uint32(cb) << 16) | (uint32(ca) << 24))
	e, ok := colorMCache[key]
	if ok {
		e.atime = now()
		return e.m
	}
	if len(colorMCache) > cacheLimit {
		oldest := int64(math.MaxInt64)
		oldestKey := colorMCacheKey(0)
		for key, c := range colorMCache {
			if c.atime < oldest {
				oldestKey = key
				oldest = c.atime
			}
		}
		delete(colorMCache, oldestKey)
	}

	cm := ebiten.ColorM{}
	rf := float64(cr) / float64(ca)
	gf := float64(cg) / float64(ca)
	bf := float64(cb) / float64(ca)
	af := float64(ca) / 0xff
	cm.Scale(rf, gf, bf, af)
	e = &colorMCacheEntry{
		m:     cm,
		atime: now(),
	}
	colorMCache[key] = e

	return e.m
}
