package router

import "testing"

func TestParseTaskCapture(t *testing.T) {
	cases := []struct {
		in     string
		text   string
		weight int
		ok     bool
	}{
		{"добавь в задачи купить молоко", "купить молоко", 0, true},
		{"Добавь в список дел: позвонить в банк", "позвонить в банк", 0, true},
		{"запиши задачу починить кран.", "починить кран", 0, true},
		{"новая задача — оплатить интернет", "оплатить интернет", 0, true},
		{"add a task buy milk", "buy milk", 0, true},
		// Urgency he stated out loud, leading or trailing, stripped from the text.
		{"добавь в задачи срочно оплатить интернет", "оплатить интернет", 3, true},
		{"добавь в задачи оплатить интернет срочно", "оплатить интернет", 3, true},
		{"новая задача важно позвонить маме", "позвонить маме", 2, true},
		// The stem inside the task text is part of the task, not a marker.
		{"добавь в задачи позвонить в срочную помощь", "позвонить в срочную помощь", 0, true},
		// Whisper punctuates dictated Russian. The marker used to be missed as
		// soon as anything sat next to it, and then it stayed in the task text
		// and in the dedupe key — the exact task he was trying to flag.
		{"добавь в задачи оплатить интернет, срочно", "оплатить интернет", 3, true},
		{"добавь в задачи очень срочно оплатить интернет", "оплатить интернет", 3, true},
		{"добавь в задачи оплатить интернет — важно", "оплатить интернет", 2, true},
		// A dictated question mark is not part of the task.
		{"добавь в задачи позвонить в банк?", "позвонить в банк", 0, true},
		// The phrasings he uses that the prefix list did not have.
		{"поставь задачу вынести мусор", "вынести мусор", 0, true},
		{"добавь в тудушки купить лампочки", "купить лампочки", 0, true},
		// A marker with nothing after it files nothing.
		{"добавь в задачи", "", 0, false},
		{"новая задача", "", 0, false},
		{"добавь в задачи срочно", "", 0, false},
		// Not a capture: he is talking, not filing.
		{"надо бы поспать", "", 0, false},
		{"я не добавил молоко в список", "", 0, false},
		{"какие у меня задачи?", "", 0, false},
		{"", "", 0, false},
	}
	for _, c := range cases {
		got, ok := ParseTaskCapture(c.in)
		if ok != c.ok || got.Text != c.text || got.Weight != c.weight {
			t.Errorf("ParseTaskCapture(%q) = (%+v, %v), want (%q, w=%d, %v)", c.in, got, ok, c.text, c.weight, c.ok)
		}
	}
}

func TestIsTaskListQuery(t *testing.T) {
	yes := []string{
		"какие у меня задачи?",
		"что мне нужно сделать?",
		"покажи список дел",
		"сколько у меня задач?",
		"задачи",
		"мои задачи",
		"what should I do",
		"что мне делать?",
	}
	for _, s := range yes {
		if !IsTaskListQuery(s) {
			t.Errorf("IsTaskListQuery(%q) = false, want true", s)
		}
	}
	no := []string{
		"как дела?",
		// No task noun and no pronoun: these fired ahead of recall and the
		// model, and answered a question about a file or a server with
		// "задач нет."
		"что нужно сделать чтобы перезапустить сервер?",
		"что мне сделать с этим файлом?",
		"what does docker do?",
		"what do you do?",
		"какая погода?",
		"напомни мне позвонить маме в шесть",
		"я сделал зарядку",
		"",
	}
	for _, s := range no {
		if IsTaskListQuery(s) {
			t.Errorf("IsTaskListQuery(%q) = true, want false", s)
		}
	}
}

// TestTaskCaptureGrammarClaimsTheMarker — the capture marker is answered at
// stage 0, so the model never gets to call it an act (Vikunja #467).
func TestTaskCaptureGrammarClaimsTheMarker(t *testing.T) {
	g := TaskCaptureGrammar()
	captures := map[string]string{
		"добавь в задачи купить молоко":       "купить молоко",
		"запиши в список дел купить хлеб":     "купить хлеб",
		"поставь задачу вынести мусор":        "вынести мусор",
		"добавь в задачи срочно оплатить дом": "оплатить дом",
	}
	for in, want := range captures {
		m := g.Pattern.FindStringSubmatch(in)
		if m == nil {
			t.Fatalf("%q did not match the grammar pattern", in)
		}
		d, ok := g.Build(m)
		if !ok {
			t.Fatalf("%q must be claimed as a capture", in)
		}
		if d.Intent != IntentNote || d.Slots.Text != want {
			t.Errorf("%q → intent=%s text=%q, want note/%q", in, d.Intent, d.Slots.Text, want)
		}
	}
	// Everything without a marker falls through, including a marker with no
	// task after it and a question about the list.
	for _, in := range []string{"надо бы поспать", "добавь в задачи", "какие у меня задачи?", "перезапусти nginx"} {
		if m := g.Pattern.FindStringSubmatch(in); m != nil {
			if _, ok := g.Build(m); ok {
				t.Errorf("%q must fall through to the cascade", in)
			}
		}
	}
}

// TestTaskListGrammarClaimsTheAsk — a list question answered before the model,
// including the phrasings with no possessive that used to route elsewhere.
func TestTaskListGrammarClaimsTheAsk(t *testing.T) {
	g := TaskListGrammar()
	claimed := []string{"какие у меня задачи", "список дел", "что мне нужно сделать"}
	for _, u := range claimed {
		m := g.Pattern.FindStringSubmatch(u)
		if m == nil {
			t.Fatalf("%q did not match the grammar pattern", u)
		}
		d, ok := g.Build(m)
		if !ok || d.Intent != IntentQuery {
			t.Errorf("%q built %+v ok=%v; want a query", u, d, ok)
		}
	}
	passed := []string{"как дела", "напомни купить хлеб", "что docker делает"}
	for _, u := range passed {
		m := g.Pattern.FindStringSubmatch(u)
		if _, ok := g.Build(m); ok {
			t.Errorf("%q was claimed as a task list", u)
		}
	}
}
