package i18n

import (
	"fmt"
	"sync"
)

// DefaultLang is the fallback language used when a requested key is missing
// in the active language.
const DefaultLang = "zh-CN"

// Translator manages localized message bundles and provides formatted message
// lookup for a given language.
type Translator struct {
	lang string
	mu   sync.RWMutex
	data map[string]map[string]string
}

// New creates a Translator initialised with DefaultLang and an empty message store.
func New() *Translator {
	return &Translator{
		lang: DefaultLang,
		data: make(map[string]map[string]string),
	}
}

// SetLang changes the active language for subsequent Get calls.
func (t *Translator) SetLang(lang string) {
	t.mu.Lock()
	defer t.mu.Unlock()
	t.lang = lang
}

// Lang returns the currently active language.
func (t *Translator) Lang() string {
	t.mu.RLock()
	defer t.mu.RUnlock()
	return t.lang
}

// Register adds a set of key-value message pairs for the given language.
// Existing entries for the same language are overwritten.
func (t *Translator) Register(lang string, messages map[string]string) {
	t.mu.Lock()
	defer t.mu.Unlock()
	if t.data[lang] == nil {
		t.data[lang] = make(map[string]string)
	}
	for k, v := range messages {
		t.data[lang][k] = v
	}
}

// Get looks up a message by key in the active language, falling back to
// DefaultLang. If args are provided the message is treated as a format
// string. When no translation is found the key itself is returned.
func (t *Translator) Get(key string, args ...any) string {
	t.mu.RLock()
	defer t.mu.RUnlock()

	langs := []string{t.lang, DefaultLang}
	for _, lang := range langs {
		if msgs, ok := t.data[lang]; ok {
			if msg, ok := msgs[key]; ok {
				if len(args) > 0 {
					return fmt.Sprintf(msg, args...)
				}
				return msg
			}
		}
	}
	return key
}

var global = New()

// SetLang changes the active language on the global Translator.
func SetLang(lang string) { global.SetLang(lang) }

// Lang returns the currently active language from the global Translator.
func Lang() string { return global.Lang() }

// Register adds message pairs for the given language on the global Translator.
func Register(lang string, messages map[string]string) { global.Register(lang, messages) }

// Get looks up a formatted message on the global Translator.
func Get(key string, args ...any) string { return global.Get(key, args...) }

func init() {
	Register("zh-CN", zhCN)
	Register("en", en)
	Register("ja", ja)
	Register("zh-CN", runtimeErrorsZhCN)
	Register("en", runtimeErrorsEN)
	Register("ja", runtimeErrorsEN)
}
