package phraser

import (
	"math/rand"
	"strconv"
	"strings"
	"testing"
)

func loadTestActs(t *testing.T) *Acts {
	t.Helper()
	a, err := LoadActs(rand.NewSource(1))
	if err != nil {
		t.Fatalf("LoadActs: %v", err)
	}
	return a
}

// She talks about a lamp or a server, never about a row in a schema. «сущность»
// and «экосистема» are the same defect as saying a capability id out loud.
func TestNoActLineSaysASchemaWord(t *testing.T) {
	a := loadTestActs(t)
	for _, v := range a.Variants() {
		for _, word := range []string{"сущност", "экосистем"} {
			if strings.Contains(v, word) {
				t.Errorf("variant %q says %q out loud", v, word)
			}
		}
	}
}

// Nexus, Praxis and Hexis fail independently, so "не отвечает" with no subject
// is not an answer he can act on.
func TestAServiceFailureNamesTheService(t *testing.T) {
	a := loadTestActs(t)
	for _, key := range []string{EcoDown, EcoDenied} {
		got := a.Say(key, map[string]string{"name": "Praxis"})
		if !strings.HasPrefix(got, "Praxis ") {
			t.Errorf("%s = %q, want it to name the service", key, got)
		}
	}
}

// A confirmation prompt for a destructive act is the worst place for an unfilled
// placeholder, so the two names it interpolates are distinct keys and both are
// declared.
func TestConfirmEntityFillsBothNames(t *testing.T) {
	a := loadTestActs(t)
	got := a.Say(ActConfirmEntity, map[string]string{
		"name": "restart", "name_entity": "Muzick indexer",
	})
	if strings.ContainsAny(got, "{}") {
		t.Fatalf("act_confirm_entity = %q, want no placeholder left", got)
	}
	if !strings.Contains(got, "restart") || !strings.Contains(got, "Muzick indexer") {
		t.Fatalf("act_confirm_entity = %q, want both names", got)
	}
}

// home_dark counts unreachable devices, and Russian inflects the noun after the
// number: the count goes in {count} and the noun comes from the helper.
func TestHomeDarkCountsWithTheHelper(t *testing.T) {
	a := loadTestActs(t)
	for n, want := range map[int]string{1: "1 устройство", 2: "2 устройства", 5: "5 устройств"} {
		got := a.Say(HomeDark, map[string]string{"count": strconv.Itoa(n), "word": Devices(n)})
		if !strings.Contains(got, want) {
			t.Errorf("home_dark for %d = %q, want %q in it", n, got, want)
		}
	}
}

// Four truths, four entries: a failure must not be able to report itself as a
// success, and an empty result must not read as a failure.
func TestActOutcomesStayDistinct(t *testing.T) {
	a := loadTestActs(t)
	seen := map[string]string{}
	for _, key := range actKeys {
		for _, v := range a.d.VariantsOf(key) {
			if prev, dup := seen[v]; dup {
				t.Errorf("%s and %s both say %q", prev, key, v)
			}
			seen[v] = key
		}
	}
}
