package action

import (
	tea "github.com/charmbracelet/bubbletea"
)

// Model defines the interface for editor state that actions can modify
type Model interface {
	// Text buffer
	Lines() []string
	Line(idx int) string
	SetLine(idx int, content string)
	InsertLine(idx int, content string)
	DeleteLine(idx int)
	LineCount() int

	// Cursor
	CursorX() int
	CursorY() int
	SetCursorX(x int)
	SetCursorY(y int)
	ClampCursorX()

	// Windows
	Windows() []*Window
	ActiveWindowId() int
	ActiveWindow() *Window

	// Window
	ScrollY() int
	SetScrollY(y int)
	WinH() int
	WinW() int
	ViewPortH() int

	// Anchor
	AnchorX() int
	AnchorY() int
	SetAnchorX(x int)
	SetAnchorY(y int)

	// Insert
	InsertKeys() []string
	SetInsertKeys(keys []string)

	// Command mode
	Command() string
	SetCommand(cmd string)
	CommandCursor() int
	SetCommandCursor(cur int)
	CommandError() error
	SetCommandError(err error)
	CommandOutput() string
	SetCommandOutput(out string)

	// Settings
	Settings() Settings
	SetSettings(s Settings)

	// Registers
	Registers() map[rune]Register
	GetRegister(name rune) (Register, bool)
	SetRegister(name rune, t RegisterType, cnt []string) error
	UpdateDefaultRegister(t RegisterType, cnt []string)

	// Mode
	Mode() Mode
	SetMode(mode Mode)

	// Insert recording (for count replay)
	SetInsertRecording(count int, action Action)

	// ExitInsertMode handles replay, cursor step-back, and mode transition on esc
	ExitInsertMode()
}

// Position represents a location in the buffer
type Position struct {
	Line, Col int
}

// MotionType indicates how a motion operates
type MotionType int

const (
	CharwiseExclusive MotionType = iota // w, b, h, l, 0, ^ - end position not included
	CharwiseInclusive                   // e, $, f - end position is included
	Linewise                            // j, k, G, gg, {, } - operates on whole lines
)

// IsCharwise returns true if the motion type is character-based (not linewise)
func (mt MotionType) IsCharwise() bool {
	return mt == CharwiseExclusive || mt == CharwiseInclusive
}

// Action is the base interface - anything executable
type Action interface {
	Execute(m Model) tea.Cmd
}

// Motion moves the cursor and returns the range covered
type Motion interface {
	Action
	Type() MotionType
}

// Operator acts on a range (delete, yank, change)
type Operator interface {
	Operate(m Model, start, end Position, mtype MotionType) tea.Cmd
}

// DoublePresser is an optional interface for operators that support double-press (dd, yy, cc)
type DoublePresser interface {
	DoublePress(m Model, count int) tea.Cmd
}

// Repeatable actions track count
type Repeatable interface {
	WithCount(n int) Action
}
