package ugh_test

import (
	"io"
	"sync"
	"testing"

	"charm.land/huh/v2"
	"git.sr.ht/~timofurrer/ugh"
)

func TestMultipleFieldsInGroup(t *testing.T) {
	t.Parallel()

	var (
		name    string
		age     string
		confirm bool
	)

	c := newTestConsole(t)
	c.Expect(ugh.Input("Name")).
		Do(ugh.Type("Eve")).
		Expect(ugh.Input("Age")).
		Do(ugh.Type("30")).
		Expect(ugh.Confirm("Correct?")).
		Do(ugh.Affirm)

	runTestForm(t, c,
		huh.NewGroup(
			huh.NewInput().
				Title("Name").
				Value(&name),
			huh.NewInput().
				Title("Age").
				Value(&age),
			huh.NewConfirm().
				Title("Correct?").
				Value(&confirm),
		),
	)

	if name != "Eve" {
		t.Fatalf("name: expected %q, got %q", "Eve", name)
	}
	if age != "30" {
		t.Fatalf("age: expected %q, got %q", "30", age)
	}
	if !confirm {
		t.Fatal("confirm: expected true")
	}
}

func TestMultipleFieldsInGroup_SelectAndInput(t *testing.T) {
	t.Parallel()

	var (
		color string
		note  string
	)

	c := newTestConsole(t)
	c.Expect(ugh.Select("Color")).
		Do(ugh.SelectIndex(1)).
		Expect(ugh.Input("Note")).
		Do(ugh.Type("nice"))

	runTestForm(t, c,
		huh.NewGroup(
			huh.NewSelect[string]().
				Title("Color").
				Options(huh.NewOptions("Red", "Blue")...).
				Value(&color),
			huh.NewInput().
				Title("Note").
				Value(&note),
		),
	)

	if color != "Blue" {
		t.Fatalf("color: expected %q, got %q", "Blue", color)
	}
	if note != "nice" {
		t.Fatalf("note: expected %q, got %q", "nice", note)
	}
}

// ---------------------------------------------------------------------------
// Start (async)
// ---------------------------------------------------------------------------

func TestStart_Async(t *testing.T) {
	t.Parallel()

	appInR, appInW := io.Pipe()
	appOutR, appOutW := io.Pipe()
	var name string

	c := newTestConsole(t)
	c.Expect(ugh.Input("Name")).
		Do(ugh.Type("Async"))

	wait := c.Start(t.Context(), appOutR, appInW)
	func() {
		defer appOutW.Close() //nolint:errcheck
		_ = newTestForm(appInR, appOutW,
			huh.NewGroup(
				huh.NewInput().Title("Name").Value(&name),
			),
		).Run()
	}()
	wait()

	if name != "Async" {
		t.Fatalf("expected %q, got %q", "Async", name)
	}
}

func TestStart_MultipleSequentialForms(t *testing.T) {
	t.Parallel()

	appInR, appInW := io.Pipe()
	appOutR, appOutW := io.Pipe()
	var name string
	var confirmed bool

	const expectedName = "Alice"

	c := newTestConsole(t)
	c.Expect(ugh.Input("Name")).
		Do(ugh.Type(expectedName)).
		Expect(ugh.Confirm("OK?")).
		Do(ugh.Affirm)

	wait := c.Start(t.Context(), appOutR, appInW)
	var wg sync.WaitGroup
	wg.Go(func() {
		defer appOutW.Close() //nolint:errcheck
		_ = newTestForm(appInR, appOutW,
			huh.NewGroup(huh.NewInput().Title("Name").Value(&name)),
		).Run()

		_ = newTestForm(appInR, appOutW,
			huh.NewGroup(huh.NewConfirm().Title("OK?").Value(&confirmed)),
		).Run()
	})
	wg.Wait()
	wait()

	if name != expectedName {
		t.Fatalf("name: expected %q, got %q", expectedName, name)
	}

	if !confirmed {
		t.Fatal("expected confirmed")
	}
}
