// Package main — weatherq.go holds the weather-query keyword helpers: does
// this utterance ask about weather at all, and which place (if any) did he
// name. Both are plain keyword matching, not NLU — extend this file rather
// than voice.go for anything in that shape.
package main

import (
	"regexp"
	"strings"
)

// isWeatherQuery returns true if the utterance is about weather.
func isWeatherQuery(u string) bool {
	lower := strings.ToLower(u)
	return strings.Contains(lower, "погод") ||
		strings.Contains(lower, "градус") ||
		strings.Contains(lower, "температур") ||
		strings.Contains(lower, "дожд") ||
		strings.Contains(lower, "холод") ||
		strings.Contains(lower, "тепл") ||
		strings.Contains(lower, "weather") ||
		strings.Contains(lower, "temperature")
}

// weatherPlace — the place he named, after "в"/"во"/"in". One or two words,
// letters and dashes only, so "в Нижнем Новгороде" and "in New York" both
// come through whole and "в 5 утра" does not.
var weatherPlace = regexp.MustCompile(`(?i)(?:^|\s)(?:в|во|in)\s+([\p{L}-]+(?:\s+[\p{L}-]+)?)`)

// weatherNonPlaces — words that follow "в" in a weather question and are not
// cities. "какая погода в доме" is the smart-home sensor, not Open-Meteo, and
// "тепло в комнате" is the same question about the same room.
var weatherNonPlaces = map[string]bool{
	"доме": true, "квартире": true, "комнате": true, "спальне": true,
	"гостиной": true, "кухне": true, "гараже": true, "офисе": true,
	"выходные": true, "субботу": true, "воскресенье": true, "понедельник": true,
	"вторник": true, "среду": true, "четверг": true, "пятницу": true,
	"обед": true, "обеде": true, "утро": true, "утром": true, "вечер": true,
	"вечером": true, "ночь": true, "ночью": true, "целом": true, "принципе": true,
}

// extractWeatherLocation returns the place he named, or the configured default
// when he named none. It returns "" when he named none AND no default is
// configured — the caller must then say it does not know.
//
// It used to be a hand-written table of six cities in two spellings each
// (Vikunja #421). Anything outside it — Kazan, Tbilisi — was dropped silently
// and answered for the default location, which reads as a correct answer about
// the wrong place. There is a geocoder behind this now: internal/weather
// already calls Open-Meteo's geocoding endpoint for every lookup, so any place
// it knows is a place he can ask about, and the table bought nothing.
//
// A named place that the geocoder cannot resolve is the caller's problem to
// report, not this function's to hide.
//
// It used to return "Moscow" when he named nothing. That is a made-up answer
// presented as fact. voice.weather.default_location is the only source of an
// unstated location.
func extractWeatherLocation(u, defaultLoc string) string {
	m := weatherPlace.FindStringSubmatch(u)
	if m == nil {
		return defaultLoc
	}
	place := strings.TrimSpace(m[1])
	first := strings.ToLower(strings.Fields(place)[0])
	if weatherNonPlaces[first] {
		return defaultLoc
	}
	return place
}
