package app

import (
	"sync"
	"time"

	tea "github.com/charmbracelet/bubbletea"
	"gokin/internal/logging"
)

// UIUpdateManager coordinates periodic UI updates
type UIUpdateManager struct {
	program          *tea.Program
	eventBroadcaster *UIEventBroadcaster

	// Control
	stopChan chan struct{}
	stopOnce sync.Once
	wg       sync.WaitGroup
	mu       sync.RWMutex
	running  bool
}

// NewUIUpdateManager creates a new UI update manager
func NewUIUpdateManager(program *tea.Program, app *App) *UIUpdateManager {
	return &UIUpdateManager{
		program:          program,
		eventBroadcaster: NewUIEventBroadcaster(program),
		stopChan:         make(chan struct{}),
		running:          false,
	}
}

// Start begins periodic UI updates
func (m *UIUpdateManager) Start() {
	m.mu.Lock()
	defer m.mu.Unlock()

	if m.running {
		return
	}

	m.running = true
	m.stopChan = make(chan struct{})
	// Create a new stopOnce for this Start/Stop cycle
	// Note: sync.Once cannot be "reset", so we create a fresh value
	m.stopOnce = sync.Once{}
}

// Stop stops periodic UI updates
func (m *UIUpdateManager) Stop() {
	m.mu.Lock()
	if !m.running {
		m.mu.Unlock()
		return
	}
	m.running = false
	m.mu.Unlock()

	m.stopOnce.Do(func() {
		close(m.stopChan)
	})

	// Stop event broadcaster first to unblock any waiting sends
	if m.eventBroadcaster != nil {
		m.eventBroadcaster.Stop()
	}

	// Wait for goroutines with timeout.
	// done is buffered so the goroutine can always complete its send even if
	// we've already timed out — no close() needed, channel is GC'd after use.
	done := make(chan struct{}, 1)
	go func() {
		m.wg.Wait()
		select {
		case done <- struct{}{}:
		default:
		}
	}()

	stopTimer := time.NewTimer(5 * time.Second)
	select {
	case <-done:
		stopTimer.Stop()
		logging.Debug("UI update manager stopped gracefully")
	case <-stopTimer.C:
		logging.Warn("UI update manager stop timed out, continuing anyway")
	}
}

// IsRunning returns whether the update manager is running
func (m *UIUpdateManager) IsRunning() bool {
	m.mu.RLock()
	defer m.mu.RUnlock()
	return m.running
}

// BroadcastTaskStart broadcasts a task start event
func (m *UIUpdateManager) BroadcastTaskStart(taskID, message, planType string) {
	m.eventBroadcaster.BroadcastTaskStart(taskID, message, planType)
}

// BroadcastTaskComplete broadcasts a task completion event
func (m *UIUpdateManager) BroadcastTaskComplete(taskID string, success bool, duration time.Duration, err error, planType string) {
	m.eventBroadcaster.BroadcastTaskComplete(taskID, success, duration, err, planType)
}

// BroadcastTaskProgress broadcasts a task progress event
func (m *UIUpdateManager) BroadcastTaskProgress(taskID string, progress float64, message string) {
	m.eventBroadcaster.BroadcastTaskProgress(taskID, progress, message)
}

// Enable enables event broadcasting
func (m *UIUpdateManager) Enable() {
	m.eventBroadcaster.Enable()
}

// Disable disables event broadcasting
func (m *UIUpdateManager) Disable() {
	m.eventBroadcaster.Disable()
}
