package i18n

import (
	"context"
	"io"

	"golang.org/x/text/language"
	"golang.org/x/text/message"
	"golang.org/x/text/message/catalog"
)

var (
	ctxLangKey  = struct{}{}
	defaultLang = language.English
	bundles     = make(map[language.Tag]Bundle, 32)
)

type Bundle struct {
	p *message.Printer
}

func GetBundle(lang language.Tag) Bundle {
	b, ok := bundles[lang]
	if !ok {
		b = bundles[defaultLang]
	}

	return b
}

func InitLanguage(lang language.Tag, catalog catalog.Catalog) Bundle {
	t, _, _ := catalog.Matcher().Match(language.Persian)
	bundles[lang] = Bundle{
		p: message.NewPrinter(t),
	}

	return bundles[lang]
}

func InjectContext(ctx context.Context, lang language.Tag) context.Context {
	return context.WithValue(ctx, ctxLangKey, lang)
}

func SetDefaultLanguage(lang language.Tag) {
	defaultLang = lang
}

func (b Bundle) Sprintf(msg message.Reference, args ...any) string {
	return b.p.Sprintf(msg, args...)
}

func (b Bundle) Fprintf(w io.Writer, key message.Reference, args ...any) (int, error) {
	return b.p.Fprintf(w, key, args...)
}

func Text(msg message.Reference, args ...any) string {
	return GetBundle(defaultLang).Sprintf(msg, args...)
}

func TextCtx(ctx context.Context, msg message.Reference, args ...any) string {
	lang, ok := ctx.Value(ctxLangKey).(language.Tag)
	if !ok {
		return Text(msg, args...)
	}

	return GetBundle(lang).Sprintf(msg, args...)
}

func TextLang(lang language.Tag, msg message.Reference, args ...any) string {
	return GetBundle(lang).Sprintf(msg, args...)
}

func Txt(msg message.Reference, args ...any) string {
	return Text(msg, args...)
}

func TxtX(ctx context.Context, msg message.Reference, args ...any) string {
	return TextCtx(ctx, msg, args...)
}

func TxtL(lang language.Tag, msg message.Reference, args ...any) string {
	return TextLang(lang, msg, args...)
}
