package ui

import (
	"sync"
	"time"

	"fyne.io/fyne/v2"
)

type Debouncer struct {
	mu       sync.Mutex
	timer    *time.Timer
	duration time.Duration
	callback func()
}

func NewDebouncer(duration time.Duration, callback func()) *Debouncer {
	return &Debouncer{
		duration: duration,
		callback: callback,
	}
}

func (d *Debouncer) Trigger() {
	d.mu.Lock()
	defer d.mu.Unlock()

	if d.timer != nil {
		d.timer.Stop()
	}

	d.timer = time.AfterFunc(d.duration, func() {
		fyne.Do(d.callback)
	})
}

type Throttler struct {
	mu       sync.Mutex
	lastCall time.Time
	interval time.Duration
	callback func()
}

func NewThrottler(interval time.Duration, callback func()) *Throttler {
	return &Throttler{
		interval: interval,
		callback: callback,
	}
}

func (t *Throttler) Trigger() {
	t.mu.Lock()
	defer t.mu.Unlock()

	now := time.Now()
	if now.Sub(t.lastCall) >= t.interval {
		t.lastCall = now
		fyne.Do(t.callback)
	}
}

type LazyLoader struct {
	mu       sync.Mutex
	loaded   bool
	loading  bool
	callback func()
}

func NewLazyLoader(callback func()) *LazyLoader {
	return &LazyLoader{
		callback: callback,
	}
}

func (l *LazyLoader) Load() {
	l.mu.Lock()
	defer l.mu.Unlock()

	if l.loaded || l.loading {
		return
	}

	l.loading = true
	go func() {
		l.callback()
		l.mu.Lock()
		l.loaded = true
		l.loading = false
		l.mu.Unlock()
	}()
}

type VirtualList struct {
	items    []interface{}
	renderer func(item interface{}) fyne.CanvasObject
	visible  int
	start    int
	end      int
}

func NewVirtualList(items []interface{}, renderer func(item interface{}) fyne.CanvasObject, visible int) *VirtualList {
	return &VirtualList{
		items:    items,
		renderer: renderer,
		visible:  visible,
		end:      visible,
	}
}

func (vl *VirtualList) GetVisibleItems() []fyne.CanvasObject {
	if vl.start >= len(vl.items) {
		return []fyne.CanvasObject{}
	}

	if vl.end > len(vl.items) {
		vl.end = len(vl.items)
	}

	var result []fyne.CanvasObject
	for i := vl.start; i < vl.end; i++ {
		result = append(result, vl.renderer(vl.items[i]))
	}

	return result
}

func (vl *VirtualList) ScrollTo(index int) {
	if index < 0 {
		index = 0
	}
	if index >= len(vl.items) {
		index = len(vl.items) - 1
	}

	vl.start = index
	vl.end = index + vl.visible
	if vl.end > len(vl.items) {
		vl.end = len(vl.items)
		vl.start = vl.end - vl.visible
		if vl.start < 0 {
			vl.start = 0
		}
	}
}

type MemoryPool struct {
	mu    sync.Mutex
	items []interface{}
	new   func() interface{}
	reset func(interface{})
}

func NewMemoryPool(new func() interface{}, reset func(interface{})) *MemoryPool {
	return &MemoryPool{
		new:   new,
		reset: reset,
	}
}

func (mp *MemoryPool) Get() interface{} {
	mp.mu.Lock()
	defer mp.mu.Unlock()

	if len(mp.items) > 0 {
		item := mp.items[len(mp.items)-1]
		mp.items = mp.items[:len(mp.items)-1]
		mp.reset(item)
		return item
	}

	return mp.new()
}

func (mp *MemoryPool) Put(item interface{}) {
	mp.mu.Lock()
	defer mp.mu.Unlock()

	mp.items = append(mp.items, item)
}
