package language

import (
	"fmt"
	"sync"

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

// Type wrapper around language.Tag so that implementation details aren't leaked to consumers.
type Tag language.Tag

// Attemps to create a language Tag from the specific language code.
// If the language code fails to parse an error is returned along with the default language Tag.
func NewTag(languageCode string) (Tag, error) {
	tag, err := language.Parse(languageCode)

	if err != nil {
		return DefaultLanguage, fmt.Errorf("unrecognized language code %s", languageCode)
	}

	return Tag(tag), nil
}

func MustParse(languageCode string) Tag {
	tag, err := NewTag(languageCode)
	if err != nil {
		panic(err)
	}

	return tag
}

func (t Tag) String() string {
	return t.Inner().String()
}

func (t Tag) Inner() language.Tag {
	return language.Tag(t)
}

var (
	// The default language (en-US)
	DefaultLanguage = Tag(language.MustParse("en-US"))

	// All of the languages currently supported by Twitch
	SupportedLanguages = []Tag{
		DefaultLanguage, // Default, fallback language
		Tag(language.MustParse("bg-BG")),
		Tag(language.MustParse("cs-CZ")),
		Tag(language.MustParse("da-DK")),
		Tag(language.MustParse("de-DE")),
		Tag(language.MustParse("el-GR")),
		Tag(language.MustParse("en-GB")),
		Tag(language.MustParse("es-MX")),
		Tag(language.MustParse("es-ES")),
		Tag(language.MustParse("fi-FI")),
		Tag(language.MustParse("fr-FR")),
		Tag(language.MustParse("hu-HU")),
		Tag(language.MustParse("it-IT")),
		Tag(language.MustParse("ja-JP")),
		Tag(language.MustParse("ko-KR")),
		Tag(language.MustParse("nl-NL")),
		Tag(language.MustParse("no-NO")),
		Tag(language.MustParse("pl-PL")),
		Tag(language.MustParse("pt-BR")),
		Tag(language.MustParse("pt-PT")),
		Tag(language.MustParse("ro-RO")),
		Tag(language.MustParse("ru-RU")),
		Tag(language.MustParse("sk-SK")),
		Tag(language.MustParse("sv-SE")),
		Tag(language.MustParse("th-TH")),
		Tag(language.MustParse("tr-TR")),
		Tag(language.MustParse("vi-VN")),
		Tag(language.MustParse("zh-TW")),
		Tag(language.MustParse("zh-CN")),
	}
)

var languageMatcherOnce sync.Once
var languageMatcher language.Matcher

func getLanguageMatcher() language.Matcher {
	languageMatcherOnce.Do(func() {
		tags := make([]language.Tag, len(SupportedLanguages))

		for index, lang := range SupportedLanguages {
			tags[index] = language.Tag(lang)
		}

		matcher := language.NewMatcher(tags)
		languageMatcher = matcher
	})

	return languageMatcher
}

// Find the closest matching language supported by Twitch.
func FindMatch(language Tag) Tag {
	matcher := getLanguageMatcher()
	result, _, _ := matcher.Match(language.Inner())

	return Tag(result)
}
