//go:build darwin

package platform

/*
#cgo darwin CFLAGS: -x objective-c -fobjc-arc
#cgo darwin LDFLAGS: -framework Cocoa
#include <stdlib.h>

long  cdropPasteboardChangeCount(void);
char *cdropPasteboardReadText(int *sensitive);
void  cdropPasteboardWriteText(const char *text);
*/
import "C"

import (
	"context"
	"time"
	"unsafe"
)

// pasteboardPollInterval is how often the watcher samples the change counter.
// 400ms keeps copies feeling instant without busy-polling.
const pasteboardPollInterval = 400 * time.Millisecond

// darwinClipboard is the macOS Source: it polls NSPasteboard's changeCount for
// local copies and writes plain text back. NSPasteboard read/write off the main
// thread is the same approach the common clipboard libraries take.
type darwinClipboard struct {
	poll time.Duration
}

// NewClipboardSource returns the platform clipboard Source (macOS).
func NewClipboardSource() Source {
	return &darwinClipboard{poll: pasteboardPollInterval}
}

func (d *darwinClipboard) Watch(ctx context.Context) <-chan ClipboardEvent {
	ch := make(chan ClipboardEvent)
	go func() {
		defer close(ch)
		last := C.cdropPasteboardChangeCount()
		ticker := time.NewTicker(d.poll)
		defer ticker.Stop()
		for {
			select {
			case <-ctx.Done():
				return
			case <-ticker.C:
				cc := C.cdropPasteboardChangeCount()
				if cc == last {
					continue
				}
				last = cc

				var sensitive C.int
				cstr := C.cdropPasteboardReadText(&sensitive)
				if cstr == nil {
					continue // non-text payload (image / file) — ignore
				}
				text := C.GoString(cstr)
				C.free(unsafe.Pointer(cstr))

				select {
				case ch <- ClipboardEvent{Text: text, Sensitive: sensitive != 0}:
				case <-ctx.Done():
					return
				}
			}
		}
	}()
	return ch
}

func (d *darwinClipboard) Write(text string) error {
	c := C.CString(text)
	defer C.free(unsafe.Pointer(c))
	C.cdropPasteboardWriteText(c)
	return nil
}
