package roundimage

import (
	"context"

	"github.com/diamondburned/cchat-gtk/internal/gts/httputil"
	"github.com/diamondburned/handy"
	"github.com/gotk3/gotk3/gdk"
	"github.com/gotk3/gotk3/gtk"
)

// TODO: GIF support

// TextSetter is an interface for setting texts.
type TextSetter interface {
	SetText(text string)
}

func TrySetText(imager Imager, text string) {
	if setter, ok := imager.(TextSetter); ok {
		setter.SetText(text)
	}
}

// Avatar is a static HdyAvatar container.
type Avatar struct {
	handy.Avatar
	pixbuf *gdk.Pixbuf
	url    string
	size   int
	cancel context.CancelFunc
}

// Make a better API that allows scaling.

var (
	_ Imager                  = (*Avatar)(nil)
	_ TextSetter              = (*Avatar)(nil)
	_ httputil.ImageContainer = (*Avatar)(nil)
)

func NewAvatar(size int) *Avatar {
	avatar := Avatar{
		Avatar: *handy.AvatarNew(size, "", true),
		size:   size,
	}
	// Set the load function. This should hopefully trigger a reload.
	avatar.SetImageLoadFunc(avatar.loadFunc)

	return &avatar
}

// GetSizeRequest returns the virtual size.
func (a *Avatar) GetSizeRequest() (int, int) {
	return a.size, a.size
}

// SetSizeRequest sets the avatar size. The actual size is min(w, h).
func (a *Avatar) SetSizeRequest(w, h int) {
	var min = w
	if w > h {
		min = h
	}

	a.size = min
	a.Avatar.SetSize(min)
	a.Avatar.SetSizeRequest(w, h)
}

func (a *Avatar) loadFunc(size int) *gdk.Pixbuf {
	if a.url == "" {
		return nil
	}

	if a.pixbuf != nil && a.size == size {
		return a.pixbuf
	}

	a.size = size
	a.refetch()

	return nil
}

func (a *Avatar) refetch() {
	a.cancelCtx()

	ctx, cancel := context.WithCancel(context.Background())
	a.cancel = cancel

	httputil.AsyncImage(ctx, a, a.url)
}

func (a *Avatar) cancelCtx() {
	if a.cancel != nil {
		a.cancel()
		a.cancel = nil
	}
}

// SetRadius is a no-op.
func (a *Avatar) SetRadius(float64) {}

// SetImageURL sets the avatar's source URL and reloads it asynchronously.
func (a *Avatar) SetImageURL(url string) {
	a.url = url
	a.refetch()
}

// SetFromPixbuf sets the pixbuf.
func (a *Avatar) SetFromPixbuf(pb *gdk.Pixbuf) {
	a.cancelCtx()
	a.pixbuf = pb
	// a.Avatar.SetImageLoadFunc(a.loadFunc)
	a.Avatar.QueueDraw()
}

// SetFromAnimation sets the first frame of the animation.
func (a *Avatar) SetFromAnimation(pa *gdk.PixbufAnimation) {
	a.cancelCtx()
	a.pixbuf = pa.GetStaticImage()
	// a.Avatar.SetImageLoadFunc(a.loadFunc)
	a.Avatar.QueueDraw()
}

// GetPixbuf returns the underlying pixbuf.
func (a *Avatar) GetPixbuf() *gdk.Pixbuf {
	return a.pixbuf
}

// GetAnimation returns nil.
func (a *Avatar) GetAnimation() *gdk.PixbufAnimation {
	return nil
}

// GetImage returns nil.
func (a *Avatar) GetImage() *gtk.Image {
	return nil
}

// GetStorageType always returns IMAGE_PIXBUF.
func (a *Avatar) GetStorageType() gtk.ImageType {
	return gtk.IMAGE_PIXBUF
}
