package editor

import (
	"sync"

	"pad/internal/ui"
)

// ConfigEvent represents a window configuration change (resize, orientation).
// PixelWidth and PixelHeight are the raw pixel dimensions from Gio.
type ConfigEvent struct {
	PixelWidth  int
	PixelHeight int
}

// ScaleEvent represents a metric change (HiDPI scale factor).
type ScaleEvent struct {
	Scale float32
}

// ConfigUpdate is a common interface for all configuration updates.
// Both ConfigEvent and ScaleEvent implement this interface.
type ConfigUpdate interface {
	apply(*State)
}

func (e ConfigEvent) apply(s *State) {
	s.PixelWidth = e.PixelWidth
	s.PixelHeight = e.PixelHeight
}

func (e ScaleEvent) apply(s *State) {
	s.SetScale(e.Scale)
}

// ResultEvent represents a completed async task result.
type ResultEvent struct {
	// Future: add result fields here
}

// Logic runs the logic goroutine and provides channels for communication.
type Logic struct {
	state            *State
	configChan       chan ConfigUpdate
	frameChan        chan []ui.Element
	inputChan        chan []ui.InputEvent
	lastLineYChan    chan int // last line Y (Dp, sent as int) feedback from renderer
	resultChan       chan ResultEvent
	mu               sync.Mutex
}

// NewLogic creates a new Logic instance.
func NewLogic() *Logic {
	state := NewState()
	TheState = state
	return &Logic{
		state:           state,
		configChan:      make(chan ConfigUpdate),
		frameChan:       make(chan []ui.Element),
		inputChan:       make(chan []ui.InputEvent),
		lastLineYChan:   make(chan int),
		resultChan:      make(chan ResultEvent),
	}
}

// ConfigChan returns the unified config channel for the logic goroutine.
// Accepts ConfigEvent (size) and ScaleEvent (scale factor).
func (l *Logic) ConfigChan() chan<- ConfigUpdate {
	return l.configChan
}

// FrameChan returns the frame channel for the logic goroutine.
func (l *Logic) FrameChan() <-chan []ui.Element {
	return l.frameChan
}

// InputChan returns the input channel for the logic goroutine.
func (l *Logic) InputChan() chan<- []ui.InputEvent {
	return l.inputChan
}

// DisplayLineChan returns the last line Y feedback channel.
func (l *Logic) DisplayLineChan() chan<- int {
	return l.lastLineYChan
}

// ResultChan returns the result channel for the logic goroutine.
func (l *Logic) ResultChan() chan<- ResultEvent {
	return l.resultChan
}

// TheState is the global editor state, set once at startup.
var TheState *State

// Scale returns the current scale factor (pixels per DP).
func (l *Logic) Scale() float32 {
	return l.state.Scale()
}

// Run runs the logic goroutine loop.
func (l *Logic) Run() {
	for {
		select {
		case update := <-l.configChan:
			update.apply(l.state)
			l.frameChan <- l.state.layout()
		case y := <-l.lastLineYChan:
			l.state.LastLineY = ui.Dp(y)
			l.frameChan <- l.state.layout()
		case events := <-l.inputChan:
			for _, evt := range events {
				evt.Handler(evt.Data)
			}
			l.frameChan <- l.state.layout()
		case <-l.resultChan:
			l.frameChan <- l.state.layout()
		}
	}
}

// State returns the current state.
func (l *Logic) State() *State {
	return l.state
}
