package widgets

import (
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/layout"
	"fyne.io/fyne/v2/theme"
	"fyne.io/fyne/v2/widget"
)

type hyperlinkWrapper struct {
	widget.Hyperlink

	textWidthCached float32
	MaxWidth        float32
}

func newHyperlinkWrapper() *hyperlinkWrapper {
	h := &hyperlinkWrapper{
		Hyperlink: widget.Hyperlink{
			Text:     "",
			Wrapping: fyne.TextTruncate,
		},
		textWidthCached: -1,
	}
	h.ExtendBaseWidget(h)
	return h
}

func (h *hyperlinkWrapper) MinSize() fyne.Size {
	if h.textWidthCached < 0 {
		s := fyne.MeasureText(h.Text, theme.TextSize(), h.TextStyle)
		// the 2.7 factor is a bit of a magic number but it works ¯\_(ツ)_/¯
		h.textWidthCached = s.Width + theme.Padding()*2.7
	}
	return fyne.NewSize(fyne.Min(h.MaxWidth, h.textWidthCached), h.Hyperlink.MinSize().Height)
}

func (h *hyperlinkWrapper) SetText(text string) {
	h.Text = text
	h.textWidthCached = -1
}

func (h *hyperlinkWrapper) TypedKey(e *fyne.KeyEvent) {
	if e.Name == fyne.KeySpace {
		if h.OnTapped != nil {
			h.OnTapped()
		}
	}
}

type CustomHyperlink struct {
	widget.BaseWidget
	h *hyperlinkWrapper
	l *widget.Label

	OnTapped   func()
	NoTruncate bool
	Disabled   bool

	lastDisabled  bool
	container     *fyne.Container
	fullTextWidth float32
}

func NewCustomHyperlink() *CustomHyperlink {
	c := &CustomHyperlink{
		h:         newHyperlinkWrapper(),
		l:         widget.NewLabel(""),
		container: container.NewMax(),
	}
	c.h.OnTapped = func() {
		if c.OnTapped != nil {
			c.OnTapped()
		}
	}
	c.fullTextWidth = c.l.MinSize().Width
	c.ExtendBaseWidget(c)
	c.updateContainer(c.Disabled)
	return c
}

func (c *CustomHyperlink) SetText(text string) {
	c.l.Text = text
	lastWrapping := c.l.Wrapping
	c.l.Wrapping = fyne.TextWrapOff
	c.fullTextWidth = c.l.MinSize().Width
	c.h.SetText(text)
	c.l.Wrapping = lastWrapping
	c.Refresh()
}

func (c *CustomHyperlink) Resize(size fyne.Size) {
	c.h.MaxWidth = size.Width
	c.BaseWidget.Resize(size)
}

func (c *CustomHyperlink) Refresh() {
	if c.NoTruncate {
		c.l.Wrapping = fyne.TextWrapOff
	} else {
		c.l.Wrapping = fyne.TextTruncate
	}
	if c.lastDisabled != c.Disabled {
		c.updateContainer(c.Disabled)
		c.lastDisabled = c.Disabled
	}
	c.container.Refresh()
}

func (c *CustomHyperlink) MinSize() fyne.Size {
	if c.NoTruncate {
		return fyne.NewSize(c.fullTextWidth, c.l.MinSize().Height)
	}
	return fyne.NewSize(0, c.l.MinSize().Height)
}

func (c *CustomHyperlink) CreateRenderer() fyne.WidgetRenderer {
	return widget.NewSimpleRenderer(c.container)
}

func (c *CustomHyperlink) updateContainer(linkDisabled bool) {
	c.container.RemoveAll()
	if linkDisabled {
		c.container.Add(c.l)
	} else {
		c.container.Add(container.NewHBox(c.h, layout.NewSpacer()))
	}
}
