package editor

import (
	"sync"

	"pad/internal/ui"
)

// ConfigEvent represents a window configuration change (resize, orientation).
// Width and Height are in device-independent pixels (Dp).
type ConfigEvent struct {
	Width  ui.Dp
	Height ui.Dp
}

// 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.ScreenWidth = e.Width
	s.ScreenHeight = e.Height
	s.Elems = EditorLayout(e.Width, e.Height)
}

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

// InputEvent represents a user input event routed to an element.
type InputEvent struct {
	ElementID string
	Type      ui.InputType
	Data      any
}

// 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 []InputEvent
	resultChan chan ResultEvent
	mu         sync.Mutex
}

// NewLogic creates a new Logic instance.
// screenWidth and screenHeight are in device-independent pixels (Dp).
func NewLogic(screenWidth, screenHeight ui.Dp) *Logic {
	return &Logic{
		state:      NewState(screenWidth, screenHeight),
		configChan: make(chan ConfigUpdate),
		frameChan:  make(chan []ui.Element),
		inputChan:  make(chan []InputEvent),
		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<- []InputEvent {
	return l.inputChan
}

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

// ScreenSize returns the current screen dimensions in Dp.
func (l *Logic) ScreenSize() (ui.Dp, ui.Dp) {
	l.mu.Lock()
	defer l.mu.Unlock()
	return l.state.ScreenWidth, l.state.ScreenHeight
}

// 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:
			// Type switch to differentiate ConfigEvent vs ScaleEvent
			switch e := update.(type) {
			case ConfigEvent:
				e.apply(l.state)
				l.frameChan <- l.state.Elems
			case ScaleEvent:
				e.apply(l.state)
				l.frameChan <- l.state.Elems
			}
		case <-l.inputChan:
			// Process input (not implemented in mockup)
			l.frameChan <- l.state.Elems
		case <-l.resultChan:
			// Handle result (not implemented in mockup)
			l.frameChan <- l.state.Elems
		}
	}
}

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