package editor

import (
	"fmt"
	"math"

	"github.com/akiyosi/qt/gui"
)

// RGBA is
type RGBA struct {
	R int
	G int
	B int
	A float64
}

type HSV struct {
	H, S, V float64
}

type XYZ struct {
	X, Y, Z float64
}

func (rgba *RGBA) copy() *RGBA {
	if rgba == nil {
		return nil
	}
	return &RGBA{
		R: rgba.R,
		G: rgba.G,
		B: rgba.B,
		A: rgba.A,
	}
}

func (rgba *RGBA) equals(other *RGBA) bool {
	if rgba == nil {
		return false
	}
	if other == nil {
		return false
	}
	return rgba.R == other.R && rgba.G == other.G && rgba.B == other.B
}

func (rgba *RGBA) String() string {
	if rgba == nil {
		return ""
	}
	return fmt.Sprintf("rgba(%d, %d, %d, %f)", rgba.R, rgba.G, rgba.B, rgba.A)
}

func (rgba *RGBA) StringTransparent() string {
	if rgba == nil {
		return ""
	}
	transparent := editor.config.Editor.Transparent
	return fmt.Sprintf("rgba(%d, %d, %d, %f)", rgba.R, rgba.G, rgba.B, transparent)
}

func transparent() float64 {
	return editor.config.Editor.Transparent
}

// Hex is
func (rgba *RGBA) Hex() string {
	if rgba == nil {
		return ""
	}
	return fmt.Sprintf("#%02x%02x%02x", uint8(rgba.R), uint8(rgba.G), uint8(rgba.B))
}

// input color *RGBA, aplpha (0.0...-1.0..) int
func (rgba *RGBA) brend(color *RGBA, alpha float64) *RGBA {
	if rgba == nil {
		return nil
	}
	return &RGBA{
		R: int((float64(rgba.R) * (1.0 - alpha)) + (float64(color.R) * alpha)),
		G: int((float64(rgba.G) * (1.0 - alpha)) + (float64(color.G) * alpha)),
		B: int((float64(rgba.B) * (1.0 - alpha)) + (float64(color.B) * alpha)),
		A: 1,
	}
}

// QColor is
func (rgba *RGBA) QColor() *gui.QColor {
	if rgba == nil {
		return nil
	}
	return gui.NewQColor3(rgba.R, rgba.G, rgba.B, int(rgba.A*255))
}

func calcColor(c int) *RGBA {
	b := c & 255
	g := (c >> 8) & 255
	r := (c >> 16) & 255
	return &RGBA{
		R: r,
		G: g,
		B: b,
		A: 1,
	}
}

// func complementaryColor(rgba *RGBA) *RGBA {
// 	if rgba == nil {
// 		return &RGBA{255, 255, 255, 1}
// 	}
// 	r := float64(rgba.R)
// 	g := float64(rgba.G)
// 	b := float64(rgba.B)
// 	max := math.Max(math.Max(r, g), b)
// 	min := math.Min(math.Min(r, g), b)
// 	c := max + min
//
// 	return &RGBA{
// 		R: int(c - r),
// 		G: int(c - g),
// 		B: int(c - b),
// 		A: 1,
// 	}
// }

func invertColor(rgba *RGBA) *RGBA {
	if rgba == nil {
		return &RGBA{0, 0, 0, 1}
	}
	var r, g, b int

	r = 255 - rgba.R
	g = 255 - rgba.G
	b = 255 - rgba.B

	return &RGBA{
		R: r,
		G: g,
		B: b,
		A: rgba.A,
	}
}

func warpColor(rgba *RGBA, v int) *RGBA {
	if rgba == nil {
		return &RGBA{0, 0, 0, 1}
	}
	var r, g, b int

	if rgba.R > 128 {
		r = rgba.R + v
	} else {
		r = rgba.R - v
	}

	if rgba.G > 128 {
		g = rgba.G + v
	} else {
		g = rgba.G - v
	}

	if rgba.B > 128 {
		b = rgba.B + v
	} else {
		b = rgba.B - v
	}

	if r <= 0 {
		r = 0
	}
	if g <= 0 {
		g = 0
	}
	if b <= 0 {
		b = 0
	}

	if r >= 255 {
		r = 255
	}
	if g >= 255 {
		g = 255
	}
	if b >= 255 {
		b = 255
	}

	return &RGBA{
		R: r,
		G: g,
		B: b,
		A: rgba.A,
	}
}

func newRGBA(r int, g int, b int, a float64) *RGBA {
	return &RGBA{
		R: r,
		G: g,
		B: b,
		A: a, // Not use this value
	}
}

func (rgba *RGBA) XYZ() *XYZ {
	if rgba == nil {
		return nil
	}
	r := float64(rgba.R) / 255.0
	g := float64(rgba.G) / 255.0
	b := float64(rgba.B) / 255.0

	return &XYZ{
		X: 2.76883*r + 1.75171*g + 1.13014*b,
		Y: 1.00000*r + 4.59061*g + 0.06007*b,
		Z: 0.00000*r + 0.05651*g + 5.59417*b,
	}
}

func (rgba *RGBA) diff(t *RGBA) float64 {
	dx := rgba.XYZ().X - t.XYZ().X
	dy := rgba.XYZ().Y - t.XYZ().Y
	dz := rgba.XYZ().Z - t.XYZ().Z

	return math.Sqrt(dx*dx + dy*dy + dz*dz)
}

func (rgba *RGBA) HSV() *HSV {
	if rgba == nil {
		return nil
	}
	r := float64(rgba.R) / 255.0
	g := float64(rgba.G) / 255.0
	b := float64(rgba.B) / 255.0

	min := math.Min(r, math.Min(g, b))
	max := math.Max(r, math.Max(g, b))
	del := max - min

	v := max

	var h, s float64

	if del < 0.00001 {
		h = 0
		s = 0
		return &HSV{h, s, v}
	}
	if max > 0.0 {
		s = del / max
	} else {
		s = 0.0
		h = -1.0
		return &HSV{h, s, v}
	}

	if r >= max {
		h = (g - b) / del
	} else if g >= max {
		h = 2.0 + (b-r)/del
	} else if b >= max {
		h = 4.0 + (r-g)/del
	}
	h *= 60

	if h < 0 {
		h += 360
	}

	h = h / 360.0

	return &HSV{h, s, v}
}

func (hsv *HSV) Colorfulness() *HSV {
	if hsv == nil {
		return nil
	}
	return &HSV{
		H: hsv.H,
		S: math.Sqrt(hsv.S),
		V: math.Sqrt(hsv.V),
	}
}

func (hsv *HSV) Colorless() *HSV {
	if hsv == nil {
		return nil
	}
	return &HSV{
		H: hsv.H,
		S: math.Pow(hsv.S, 1.3),
		V: math.Pow(hsv.V, 1.3),
	}
}

func (hsv *HSV) RGB() *RGBA {
	if hsv == nil {
		return nil
	}
	var r, g, b float64
	if hsv.S == 0 {
		r = hsv.V * 255
		g = hsv.V * 255
		b = hsv.V * 255
	} else {
		h := hsv.H * 6
		if h == 6 {
			h = 0
		}
		i := math.Floor(h)
		v1 := hsv.V * (1 - hsv.S)
		v2 := hsv.V * (1 - hsv.S*(h-i))
		v3 := hsv.V * (1 - hsv.S*(1-(h-i)))

		if i == 0 {
			r = hsv.V
			g = v3
			b = v1
		} else if i == 1 {
			r = v2
			g = hsv.V
			b = v1
		} else if i == 2 {
			r = v1
			g = hsv.V
			b = v3
		} else if i == 3 {
			r = v1
			g = v2
			b = hsv.V
		} else if i == 4 {
			r = v3
			g = v1
			b = hsv.V
		} else {
			r = hsv.V
			g = v1
			b = v2
		}

		r = r * 255
		g = g * 255
		b = b * 255
	}

	return &RGBA{
		R: int(r),
		G: int(g),
		B: int(b),
		A: 1.0,
	}
}
