package i18n

import (
	"context"
	_ "embed"
	"encoding/json"
	"fmt"
	"strings"
	"sync"

	"git.dmitriygnatenko.ru/dima/go-common/logger"
	"github.com/gofiber/fiber/v2"

	"git.dmitriygnatenko.ru/dima/dmitriygnatenko-v2/internal/model"
)

//go:embed ru.json
var ruJsonContent []byte

//go:embed en.json
var enJsonContent []byte

const (
	langParam = "lang"
	ru        = "ru"
	en        = "en"
)

type Language string

var (
	once sync.Once
	i18n *I18n
)

type I18n struct {
	translations    map[Language]map[string]string
	languages       map[Language]model.Language
	defaultLanguage Language
}

func Init(req []model.Language) error {
	var err error

	once.Do(func() {
		var defaultLanguage Language
		translations := make(map[Language]map[string]string)
		languages := make(map[Language]model.Language)

		for i := range req {
			if req[i].IsDefault {
				defaultLanguage = Language(strings.ToLower(req[i].URL))
			}

			url := strings.ToLower(req[i].URL)
			languages[Language(url)] = req[i]

			switch url {
			case ru:
				ruTranslations := make(map[string]string)

				err = json.Unmarshal(ruJsonContent, &ruTranslations)
				if err != nil {
					logger.Warn(context.Background(), err.Error())
					continue
				}

				translations[Language(url)] = ruTranslations
			case en:
				enTranslations := make(map[string]string)

				err = json.Unmarshal(enJsonContent, &enTranslations)
				if err != nil {
					logger.Warn(context.Background(), err.Error())
					continue
				}

				translations[Language(url)] = enTranslations
			}
		}

		i18n = &I18n{
			translations:    translations,
			defaultLanguage: defaultLanguage,
			languages:       languages,
		}
	})

	return err
}

func T(lang Language, key string, args ...any) string {
	if i18n == nil {
		logger.Error(context.Background(), "i18n not initialized")
		return ""
	}

	if i18n.translations[lang] == nil {
		logger.Warnf(context.Background(), "i18n: language %s not initialized", lang)
		return ""
	}

	var translated string

	if len(args) == 0 {
		translated = i18n.translations[lang][key]
	} else {
		translated = fmt.Sprintf(i18n.translations[lang][key], args...)
	}

	if len(translated) == 0 {
		logger.Warnf(
			context.Background(),
			"i18n: language %s translation %s is not found", lang, key,
		)
	}

	return translated
}

func DefaultLanguage() Language {
	if i18n == nil {
		logger.Error(context.Background(), "i18n not initialized")
		return ""
	}

	return i18n.defaultLanguage
}

func LanguageFromContext(c *fiber.Ctx) Language {
	if c == nil {
		return DefaultLanguage()
	}

	language := c.Params(langParam)
	if len(language) > 0 {
		return Language(language)
	}

	return DefaultLanguage()
}

func LanguageID(lang Language) model.LanguageID {
	if i18n == nil {
		logger.Error(context.Background(), "i18n not initialized")
		return 0
	}

	if language, ok := i18n.languages[lang]; ok {
		return language.ID
	}

	logger.Errorf(
		context.Background(),
		"i18n: language ID for %s language is not found", lang,
	)

	return 0
}

func LanguageFromID(id model.LanguageID) Language {
	if i18n == nil {
		logger.Error(context.Background(), "i18n not initialized")
		return DefaultLanguage()
	}

	for lang, modelLang := range i18n.languages {
		if modelLang.ID == id {
			return lang
		}
	}

	return DefaultLanguage()
}
