package i18n

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"sync"
)

type Translator struct {
	defaultLang string
	mu          sync.RWMutex
	messages    map[string]map[string]string
}

func New(defaultLang string) *Translator {
	if defaultLang == "" {
		defaultLang = "ms"
	}
	return &Translator{
		defaultLang: defaultLang,
		messages:    make(map[string]map[string]string),
	}
}

func (t *Translator) DefaultLanguage() string {
	return t.defaultLang
}

func (t *Translator) Load(lang string, messages map[string]string) {
	t.mu.Lock()
	defer t.mu.Unlock()
	if t.messages[lang] == nil {
		t.messages[lang] = make(map[string]string)
	}
	for k, v := range messages {
		t.messages[lang][k] = v
	}
}

func (t *Translator) LoadJSON(lang string, data []byte) error {
	var messages map[string]string
	if err := json.Unmarshal(data, &messages); err != nil {
		return fmt.Errorf("i18n: parse %s: %w", lang, err)
	}
	t.Load(lang, messages)
	return nil
}

func (t *Translator) LoadDir(dir string) error {
	entries, err := os.ReadDir(dir)
	if err != nil {
		return err
	}
	for _, entry := range entries {
		if entry.IsDir() || filepath.Ext(entry.Name()) != ".json" {
			continue
		}
		lang := strings.TrimSuffix(entry.Name(), ".json")
		data, err := os.ReadFile(filepath.Join(dir, entry.Name()))
		if err != nil {
			return err
		}
		if err := t.LoadJSON(lang, data); err != nil {
			return err
		}
	}
	return nil
}

func (t *Translator) T(lang, key string) string {
	t.mu.RLock()
	defer t.mu.RUnlock()

	if msg, ok := t.messages[lang][key]; ok {
		return msg
	}
	if msg, ok := t.messages[t.defaultLang][key]; ok {
		return msg
	}
	return key
}

func (t *Translator) Tf(lang, key string, args ...any) string {
	return fmt.Sprintf(t.T(lang, key), args...)
}

func (t *Translator) Languages() []string {
	t.mu.RLock()
	defer t.mu.RUnlock()
	langs := make([]string, 0, len(t.messages))
	for lang := range t.messages {
		langs = append(langs, lang)
	}
	sort.Strings(langs)
	return langs
}
