//go:build darwin

package darwin

import (
	"errors"
	"image"
	"image/color"
	"os"
	"runtime"
	"testing"
	"time"

	"chirami/internal/platform"
)

var mainWork = make(chan func())

func runOnMain(f func()) {
	done := make(chan struct{})
	mainWork <- func() {
		f()
		close(done)
	}
	<-done
}

func TestMain(m *testing.M) {
	runtime.LockOSThread()

	var exitCode int
	go func() {
		exitCode = m.Run()
		close(mainWork)
	}()

	for work := range mainWork {
		work()
	}

	os.Exit(exitCode)
}

func TestRunLifecycleAndLocate(t *testing.T) {
	runOnMain(func() {
		ran := false
		err := Run(func(b platform.Backend) error {
			ran = true

			if b.Selections() == nil {
				t.Errorf("Selections() channel is nil")
			}
			if b.Events() == nil {
				t.Errorf("Events() channel is nil")
			}

			anchor, err := b.Locate()
			if err != nil {
				t.Errorf("Locate error: %v", err)
			}
			if anchor.Scale <= 0 {
				t.Errorf("expected scale > 0, got %f", anchor.Scale)
			}
			if anchor.Screen.W <= 0 || anchor.Screen.H <= 0 {
				t.Errorf("expected positive screen size, got %+v", anchor.Screen)
			}

			px, py, ok := b.Pointer()
			if !ok {
				t.Errorf("Pointer reported ok=false")
			}
			_ = px
			_ = py

			// Test showing a standard image
			img := image.NewRGBA(image.Rect(0, 0, 100, 100))
			img.SetRGBA(50, 50, color.RGBA{R: 255, G: 0, B: 0, A: 255})
			popup := platform.Popup{
				Image: img,
				X:     anchor.X,
				Y:     anchor.Y,
				Hit:   platform.Rect{X: 10, Y: 10, W: 80, H: 80},
			}

			if err := b.Show(popup); err != nil {
				t.Errorf("Show failed: %v", err)
			}
			time.Sleep(40 * time.Millisecond)

			// Test showing a sub-image with non-zero Min and non-tight stride
			parent := image.NewRGBA(image.Rect(0, 0, 200, 200))
			subImg := parent.SubImage(image.Rect(20, 30, 120, 110)).(*image.RGBA)
			subPopup := platform.Popup{
				Image: subImg,
				X:     anchor.X + 20,
				Y:     anchor.Y + 20,
				Hit:   platform.Rect{X: 5, Y: 5, W: 90, H: 70},
			}
			if err := b.Show(subPopup); err != nil {
				t.Errorf("Show sub-image failed: %v", err)
			}
			time.Sleep(40 * time.Millisecond)

			b.Hide()
			return nil
		})

		if err != nil {
			t.Fatalf("Run returned error: %v", err)
		}
		if !ran {
			t.Fatalf("app function was not executed")
		}
	})
}

func TestRunErrorPropagation(t *testing.T) {
	runOnMain(func() {
		sentinel := errors.New("sentinel test error")
		err := Run(func(b platform.Backend) error {
			return sentinel
		})
		if !errors.Is(err, sentinel) {
			t.Fatalf("expected %v, got %v", sentinel, err)
		}
	})
}
