// Package platform is the seam between chirami and the desktop: it watches the
// selection, finds the pointer, and shows a pre-rendered popup image.
// Each OS backend lives in a subpackage and is picked by build tags in run_*.go.
package platform

import "image"

// Rect is in logical pixels (points on macOS).
type Rect struct{ X, Y, W, H float64 }

func (r Rect) Contains(x, y float64) bool {
	return x >= r.X && y >= r.Y && x < r.X+r.W && y < r.Y+r.H
}

// Anchor is where the popup should appear.
type Anchor struct {
	X, Y   float64 // pointer position, logical px, in the same space as Screen
	Screen Rect    // usable bounds of the display under the pointer
	Scale  float64 // device px per logical px on that display
}

type EventKind int

const (
	// Click is a primary-button release inside the popup.
	Click EventKind = iota
	// Motion is pointer movement inside the popup.
	Motion
	// Leave fires when the pointer leaves the popup after having entered it.
	Leave
	// Dismiss means the user wants it gone: Escape, or a click outside the
	// popup where the backend can see one.
	Dismiss
)

// Event coordinates are logical px relative to the popup image origin.
type Event struct {
	Kind EventKind
	X, Y float64
}

// Popup is a rendered card ready to show.
type Popup struct {
	Image *image.RGBA // premultiplied RGBA, rendered at Anchor.Scale device px per logical px
	X, Y  float64     // top-left of Image in logical px, same space as Anchor
	Hit   Rect        // the opaque card inside Image (excludes the shadow), logical px relative to Image origin
}

// Backend is implemented once per windowing system. All methods are safe to
// call from any goroutine.
type Backend interface {
	// Selections delivers the selected text each time the selection settles:
	// after it changes and, where the backend can tell, once the pointer
	// button is released. The app debounces further.
	Selections() <-chan string
	// Locate reports where the pointer is now.
	Locate() (Anchor, error)
	// Pointer is a cheap current pointer position in Anchor space; ok is
	// false where the platform cannot tell (Wayland).
	Pointer() (x, y float64, ok bool)
	// Show displays p without taking keyboard focus, replacing any popup
	// already shown.
	Show(p Popup) error
	Hide()
	Events() <-chan Event
}

// Screenshotter is implemented by backends that can tell when the user takes
// a screenshot with the desktop's own tool, as opposed to any image landing
// on the clipboard.
type Screenshotter interface {
	// Screenshots delivers each screenshot the user takes, encoded as PNG.
	Screenshots() <-chan []byte
}
