package pkg

import (
	"context"
	"net/http"

	"github.com/leonelquinteros/gotext"
	"golang.org/x/text/language"
)

const contextLocaleKey = "numerus-locale"

type Locale struct {
	*gotext.Locale
	CurrencyPattern string
	Language        language.Tag
}

func NewLocale(lang availableLanguage) *Locale {
	return &Locale{
		gotext.NewLocale("locales", lang.tag.String()),
		lang.currencyPattern,
		lang.tag,
	}
}

func LocaleSetter(db *Db, next http.Handler) http.Handler {
	availableLanguages := mustGetAvailableLanguages(db)

	locales := map[language.Tag]*Locale{}
	var tags []language.Tag
	for _, lang := range availableLanguages {
		locale := NewLocale(lang)
		locale.AddDomain("numerus")
		locales[lang.tag] = locale
		tags = append(tags, lang.tag)
	}
	defaultLocale := locales[language.Catalan]
	var matcher = language.NewMatcher(tags)

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var locale *Locale
		user := getUser(r)
		locale = locales[user.Language]
		if locale == nil {
			t, _, err := language.ParseAcceptLanguage(r.Header.Get("Accept-Language"))
			if err == nil {
				tag, _, _ := matcher.Match(t...)
				var ok bool
				locale, ok = locales[tag]
				for !ok && !tag.IsRoot() {
					tag = tag.Parent()
					locale, ok = locales[tag]
				}
			}
		}
		if locale == nil {
			locale = defaultLocale
		}
		ctx := context.WithValue(r.Context(), contextLocaleKey, locale)
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

func getLocale(r *http.Request) *Locale {
	return r.Context().Value(contextLocaleKey).(*Locale)
}

func pgettext(context string, str string, locale *Locale) string {
	return locale.GetC(str, context)
}

func gettext(str string, locale *Locale) string {
	return locale.Get(str)
}

type availableLanguage struct {
	tag             language.Tag
	currencyPattern string
}

func mustGetAvailableLanguages(db *Db) []availableLanguage {
	rows, err := db.Query(context.Background(), "select lang_tag, currency_pattern from language where selectable")
	if err != nil {
		panic(err)
	}
	defer rows.Close()

	var langs []availableLanguage
	for rows.Next() {
		var langTag string
		var currencyPattern string
		err = rows.Scan(&langTag, &currencyPattern)
		if err != nil {
			panic(err)
		}
		langs = append(langs, availableLanguage{language.MustParse(langTag), currencyPattern})
	}
	if rows.Err() != nil {
		panic(rows.Err())
	}

	return langs
}
