package main

import (
	"context"
	"log"
	"regexp"

	"github.com/kami/maven/internal/phraser"
)

// A question about her — "что ты умеешь", "кто ты" — used to have no answer at
// all (Vikunja #555). It reached the personal boundary, which claimed it as his
// and said "не знаю — не нашла у тебя такой записи", because the boundary knows
// two sides and this is neither: her own description is not his data and it is
// not the world's either. Letting it past the boundary is no better, because
// then SearXNG answers about somebody else's assistant.
//
// The description does NOT live in the note store. Notes are his. A note about
// her sitting in his index would come back for "что я записал", would be fed to
// the digestion worker as something he said, and would be recalled by vector
// proximity for questions that are not about her at all. It is her own text, so
// it lives here, in one place, and it is the only copy.
//
// This source sits ABOVE the boundary, because a question about her never had
// an answer below it.

// selfDescription — what she is and what this box actually does. Frozen text,
// and the one rule for editing it: name only what is really wired. Anything
// that depends on config — the house, the LAN, the feeds, telegram, search — is
// named as depending on what he allowed, never claimed outright. Inventing a
// capability here is the same defect as inventing a fact, and it is worse than
// silence because he would plan around it.
//
// Written in her own voice, feminine, addressing him informally, because it is
// handed to the phraser as the evidence for the answer and the phraser will
// keep the words it is given.
const selfDescription = `Я Мэйвен, твоя помощница. Я живу на твоём сервере, ` +
	`и наружу уходит только поисковый запрос — больше ничего.

Что я делаю сама: запоминаю, что ты мне говоришь, и потом отвечаю на вопросы ` +
	`об этом; веду заметки; ставлю напоминания; читаю твой календарь и задачи; ` +
	`отвечаю на вопросы о мире — сначала поиском, а если сети нет, то по ` +
	`офлайновой энциклопедии.

Что зависит от того, что ты мне разрешил: дом, локальная сеть, ленты, ` +
	`список покупок, погода, телеграм. Если что-то из этого не настроено, я ` +
	`скажу об этом прямо, а не буду выдумывать ответ.

Говорю по-русски и по-английски.`

// selfSeeds — the questions this source claims. Scoring data like every other
// topic set: editing one moves the recogniser and has to be re-measured against
// TestONNXTopics.
//
// All of them are about HER — what she is, what she can do, who made her. The
// neighbouring set is topicAttend, "что требует внимания", which asks about the
// state of his things; the two share almost nothing but the second person.
var selfSeeds = []string{
	"что ты умеешь",
	"что ты можешь делать",
	"кто ты такая",
	"расскажи о себе",
	"какие у тебя возможности",
	// Added after measuring: it won self by 0.0002, under the margin, and the
	// floor does not carry it — "способна" names no verb the floor matches.
	"на что ты способна",
	"чем ты можешь помочь",
	"what can you do",
	"who are you",
}

// selfFloor — the offline floor, for a handler with no embedder or a turn whose
// vector never got computed. Narrow on purpose, like every other floor here: it
// answers only when the seeds cannot, and a broad guess made blind is worse
// than a narrow one.
//
// Go's \b is ASCII-only and never fires next to a Cyrillic letter, so the
// Russian patterns spell the boundary out.
var selfPatterns = []*regexp.Regexp{
	regexp.MustCompile(`(?i)(^|[^\p{L}\p{N}])ты\s+(умеешь|можешь)([^\p{L}\p{N}]|$)`),
	regexp.MustCompile(`(?i)(^|[^\p{L}\p{N}])кто\s+ты([^\p{L}\p{N}]|$)`),
	regexp.MustCompile(`(?i)(^|[^\p{L}\p{N}])(расскажи|поведай)\s+о\s+себе([^\p{L}\p{N}]|$)`),
	regexp.MustCompile(`(?i)\bwhat\s+can\s+you\s+do\b`),
	regexp.MustCompile(`(?i)\bwho\s+are\s+you\b`),
}

func selfFloor(utterance string) bool {
	for _, re := range selfPatterns {
		if re.MatchString(utterance) {
			return true
		}
	}
	return false
}

// querySelf answers a question about her from selfDescription. The description
// goes through the phraser as evidence so the answer is shaped to what he
// asked — "что ты умеешь" and "кто ты" want different halves of it — and falls
// back to the text itself, which is already readable, if the model is down.
func (h *reactiveHandler) querySelf(ctx context.Context, t *queryTurn) (string, bool) {
	if !h.turnIsAbout(ctx, t, topicSelf, selfFloor) {
		return "", false
	}
	var reply string
	if h.phraser != nil {
		var err error
		reply, err = h.phraser.PhraseSelf(ctx, t.dec.Utterance, selfDescription)
		if err != nil {
			log.Printf("voice: phrase self: %v", err)
		}
	}
	if reply == "" {
		reply = phraser.Q(phraser.QueryFound, map[string]string{"text": selfDescription})
	}
	return reply, true
}
