package i18nx

import (
	"embed"
	"fmt"
	"log/slog"
	"path/filepath"
	"strings"
	"sync"

	"github.com/gin-gonic/gin"
	"gopkg.in/yaml.v3"
)

//go:embed locales/*.yml
var localeFiles embed.FS

var (
	messagesOnce sync.Once
	messages     map[string]map[string]string
)

func T(ctx *gin.Context, key string, args ...any) string {
	if ctx == nil {
		return Getf(DefaultLocale, key, args...)
	}
	return Getf(Locale(ctx), key, args...)
}

func TLocale(locale string, key string, args ...any) string {
	return Getf(locale, key, args...)
}

func Get(key string) string {
	return Getf(DefaultLocale, key)
}

func Getf(locale string, key string, args ...any) string {
	format := lookup(NormalizeLocale(locale), key)
	if len(args) == 0 {
		return format
	}
	return fmt.Sprintf(format, args...)
}

func lookup(locale string, key string) string {
	loadMessages()
	if value := lookupLocale(locale, key); value != "" {
		return value
	}
	if locale != DefaultLocale {
		if value := lookupLocale(DefaultLocale, key); value != "" {
			return value
		}
	}
	slog.Warn("translation key not found", "key", key, "locale", locale)
	return key
}

func lookupLocale(locale string, key string) string {
	if values, ok := messages[locale]; ok {
		return values[key]
	}
	slog.Warn("locale not found", "locale", locale)
	return ""
}

func loadMessages() {
	messagesOnce.Do(func() {
		loaded := make(map[string]map[string]string)
		entries, err := localeFiles.ReadDir("locales")
		if err != nil {
			slog.Error("read locale files failed", "err", err)
			messages = loaded
			return
		}
		for _, entry := range entries {
			if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".yml") {
				continue
			}
			path := filepath.Join("locales", entry.Name())
			data, err := localeFiles.ReadFile(path)
			if err != nil {
				slog.Error("read locale file failed", "file", path, "err", err)
				continue
			}
			values := make(map[string]string)
			if err := yaml.Unmarshal(data, &values); err != nil {
				slog.Error("parse locale file failed", "file", path, "err", err)
				continue
			}
			locale := strings.TrimSuffix(entry.Name(), ".yml")
			loaded[NormalizeLocale(locale)] = values
		}
		messages = loaded
	})
}
