// Package input provides human-like mouse and keyboard simulation.
//
// Mouse movement uses Bézier curves with natural acceleration.
// All inputs include randomized timing to mimic human behavior.
// Platform-specific backends: SendInput (Windows), X11/uinput (Linux).
package input

import (
	"image"
	"math"
	"math/rand"
	"time"
)

// MouseController handles human-like mouse movement and clicks.
type MouseController struct {
	humanizer *Humanizer
}

// NewMouseController creates a mouse controller with the given humanizer.
func NewMouseController(h *Humanizer) *MouseController {
	return &MouseController{humanizer: h}
}

// MoveTo moves the mouse to target using a Bézier curve.
func (m *MouseController) MoveTo(target image.Point) {
	// Get current position
	current := m.GetPosition()

	// Generate Bézier control points
	points := m.bezierPath(current, target)

	// Animate along the path
	speed := m.humanizer.MouseSpeed()
	totalDist := m.pathLength(points)
	steps := int(totalDist / speed * 1000) // ms-based steps
	if steps < 5 {
		steps = 5
	}

	for i := 1; i <= steps; i++ {
		t := float64(i) / float64(steps)
		// Ease in-out for natural acceleration
		t = m.easeInOut(t)
		p := m.evalBezier(points, t)
		m.setPosition(p)
		time.Sleep(time.Millisecond)
	}
}

// Click performs a mouse click at the current position.
func (m *MouseController) Click() {
	m.humanizer.Wait()
	// TODO: Platform-specific click (SendInput / X11)
	// Randomize hold duration
	holdMs := 50 + rand.Intn(80)
	time.Sleep(time.Duration(holdMs) * time.Millisecond)
}

// ClickAt moves to position and clicks.
func (m *MouseController) ClickAt(pos image.Point) {
	jittered := m.humanizer.JitterPosition(pos)
	m.MoveTo(jittered)
	m.Click()
}

// RightClick performs a right mouse click.
func (m *MouseController) RightClick() {
	m.humanizer.Wait()
	holdMs := 50 + rand.Intn(80)
	time.Sleep(time.Duration(holdMs) * time.Millisecond)
}

// GetPosition returns current mouse position.
func (m *MouseController) GetPosition() image.Point {
	// TODO: Platform-specific implementation
	return image.Point{}
}

func (m *MouseController) setPosition(p image.Point) {
	// TODO: Platform-specific implementation
}

// bezierPath generates a cubic Bézier curve with randomized control points.
func (m *MouseController) bezierPath(start, end image.Point) [4]image.Point {
	dx := float64(end.X - start.X)
	dy := float64(end.Y - start.Y)

	// Randomize control points for natural curvature
	cp1 := image.Point{
		X: start.X + int(dx*0.25+rand.Float64()*50-25),
		Y: start.Y + int(dy*0.25+rand.Float64()*50-25),
	}
	cp2 := image.Point{
		X: start.X + int(dx*0.75+rand.Float64()*50-25),
		Y: start.Y + int(dy*0.75+rand.Float64()*50-25),
	}

	return [4]image.Point{start, cp1, cp2, end}
}

// evalBezier evaluates a cubic Bézier curve at parameter t.
func (m *MouseController) evalBezier(pts [4]image.Point, t float64) image.Point {
	u := 1 - t
	return image.Point{
		X: int(u*u*u*float64(pts[0].X) + 3*u*u*t*float64(pts[1].X) + 3*u*t*t*float64(pts[2].X) + t*t*t*float64(pts[3].X)),
		Y: int(u*u*u*float64(pts[0].Y) + 3*u*u*t*float64(pts[1].Y) + 3*u*t*t*float64(pts[2].Y) + t*t*t*float64(pts[3].Y)),
	}
}

// easeInOut applies ease-in-out for natural mouse acceleration.
func (m *MouseController) easeInOut(t float64) float64 {
	return t * t * (3 - 2*t)
}

func (m *MouseController) pathLength(pts [4]image.Point) float64 {
	length := 0.0
	prev := pts[0]
	for i := 1; i <= 20; i++ {
		t := float64(i) / 20.0
		p := m.evalBezier(pts, t)
		dx := float64(p.X - prev.X)
		dy := float64(p.Y - prev.Y)
		length += math.Sqrt(dx*dx + dy*dy)
		prev = p
	}
	return length
}

// KeyboardController handles human-like keyboard input.
type KeyboardController struct {
	humanizer *Humanizer
}

// NewKeyboardController creates a keyboard controller.
func NewKeyboardController(h *Humanizer) *KeyboardController {
	return &KeyboardController{humanizer: h}
}

// PressKey presses and releases a key with human-like timing.
func (k *KeyboardController) PressKey(key string) {
	k.humanizer.Wait()
	// TODO: Platform-specific key press
	holdMs := 30 + rand.Intn(70)
	time.Sleep(time.Duration(holdMs) * time.Millisecond)
}

// TypeText types text with randomized inter-key delays.
func (k *KeyboardController) TypeText(text string) {
	for _, ch := range text {
		k.PressKey(string(ch))
		delay := 30 + rand.Intn(120) // 30-150ms between keys
		time.Sleep(time.Duration(delay) * time.Millisecond)
	}
}

// HoldKey holds a key down for a duration.
func (k *KeyboardController) HoldKey(key string, durationMs int) {
	// TODO: Platform-specific key down/up
	variance := rand.Intn(durationMs / 5)
	time.Sleep(time.Duration(durationMs+variance) * time.Millisecond)
}
