// Package input — humanize.go provides human-like behavior randomization.
package input

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

// HumanProfile defines behavior parameters for human-like input.
type HumanProfile struct {
	ReactionMin      time.Duration // min reaction delay
	ReactionMax      time.Duration // max reaction delay
	MouseSpeedMin    float64       // min pixels per second
	MouseSpeedMax    float64       // max pixels per second
	ClickJitter      int           // pixel jitter on clicks
	HesitationChance float64       // chance of extra pause (0-1)
	HesitationMin    time.Duration
	HesitationMax    time.Duration
}

// DefaultProfile returns a realistic human behavior profile.
func DefaultProfile() HumanProfile {
	return HumanProfile{
		ReactionMin:      150 * time.Millisecond,
		ReactionMax:      450 * time.Millisecond,
		MouseSpeedMin:    400,
		MouseSpeedMax:    1200,
		ClickJitter:      3,
		HesitationChance: 0.1,
		HesitationMin:    300 * time.Millisecond,
		HesitationMax:    1200 * time.Millisecond,
	}
}

// Humanizer applies human-like randomization to bot actions.
type Humanizer struct {
	Profile     HumanProfile
	actionCount atomic.Int64
}

// NewHumanizer creates a humanizer with the given profile.
func NewHumanizer(profile HumanProfile) *Humanizer {
	return &Humanizer{Profile: profile}
}

// ReactionDelay returns a randomized human-like reaction delay.
func (h *Humanizer) ReactionDelay() time.Duration {
	minMs := h.Profile.ReactionMin.Milliseconds()
	maxMs := h.Profile.ReactionMax.Milliseconds()
	base := time.Duration(minMs+rand.Int63n(maxMs-minMs)) * time.Millisecond

	// Occasional hesitation
	if rand.Float64() < h.Profile.HesitationChance {
		hesMinMs := h.Profile.HesitationMin.Milliseconds()
		hesMaxMs := h.Profile.HesitationMax.Milliseconds()
		base += time.Duration(hesMinMs+rand.Int63n(hesMaxMs-hesMinMs)) * time.Millisecond
	}

	// Slight fatigue factor
	actions := float64(h.actionCount.Load())
	fatigue := min(actions/1000.0, 0.3)
	base = time.Duration(float64(base) * (1 + fatigue*rand.Float64()))

	return base
}

// Wait pauses for a human-like reaction delay.
func (h *Humanizer) Wait() {
	time.Sleep(h.ReactionDelay())
	h.actionCount.Add(1)
}

// WaitMs pauses for baseMs ± varianceMs with human randomization.
func (h *Humanizer) WaitMs(baseMs, varianceMs int) {
	actual := baseMs + rand.Intn(2*varianceMs+1) - varianceMs
	if actual < 0 {
		actual = 0
	}
	time.Sleep(time.Duration(actual) * time.Millisecond)
}

// JitterPosition adds random offset to a click position.
func (h *Humanizer) JitterPosition(pos image.Point) image.Point {
	j := h.Profile.ClickJitter
	return image.Point{
		X: pos.X + rand.Intn(2*j+1) - j,
		Y: pos.Y + rand.Intn(2*j+1) - j,
	}
}

// MouseSpeed returns a randomized mouse movement speed.
func (h *Humanizer) MouseSpeed() float64 {
	return h.Profile.MouseSpeedMin + rand.Float64()*(h.Profile.MouseSpeedMax-h.Profile.MouseSpeedMin)
}

func min(a, b float64) float64 {
	if a < b {
		return a
	}
	return b
}
