package middleware

import (
	"strconv"
	"strings"

	"git.ma-al.com/goc_daniel/b2b/app/service/langsService"
	"github.com/gofiber/fiber/v3"
)

// LanguageMiddleware discovers client's language and stores it in context
// Priority: Query param > Cookie > Accept-Language header > Default language
func LanguageMiddleware() fiber.Handler {
	langService := langsService.LangSrv

	return func(c fiber.Ctx) error {
		var langID uint

		// 1. Check query parameter
		langIDStr := c.Query("lang_id", "")
		if langIDStr != "" {
			if id, err := strconv.ParseUint(langIDStr, 10, 32); err == nil {
				langID = uint(id)
				if langID > 0 {
					lang, err := langService.GetLanguageById(langID)
					if err == nil {
						c.Locals("langID", langID)
						c.Locals("lang", lang)
						return c.Next()
					}
				}
			}
		}

		// 2. Check cookie
		cookieLang := c.Cookies("lang_id", "")
		if cookieLang != "" {
			if id, err := strconv.ParseUint(cookieLang, 10, 32); err == nil {
				langID = uint(id)
				if langID > 0 {
					lang, err := langService.GetLanguageById(langID)
					if err == nil {
						c.Locals("langID", langID)
						c.Locals("lang", lang)
						return c.Next()
					}
				}
			}
		}

		// 3. Check Accept-Language header
		acceptLang := c.Get("Accept-Language", "")
		if acceptLang != "" {
			// Parse the Accept-Language header (e.g., "en-US,en;q=0.9,pl;q=0.8")
			isoCode := parseAcceptLanguage(acceptLang)
			if isoCode != "" {
				lang, err := langService.GetLanguageByISOCode(isoCode)
				if err == nil && lang != nil {
					langID = uint(lang.ID)
					c.Locals("langID", langID)
					c.Locals("lang", lang)
					return c.Next()
				}
			}
		}

		// 4. Fall back to default language
		defaultLang, err := langService.GetDefaultLanguage()
		if err == nil && defaultLang != nil {
			langID = uint(defaultLang.ID)
			c.Locals("langID", langID)
			c.Locals("lang", defaultLang)
		}

		return c.Next()
	}
}

// parseAcceptLanguage extracts the primary language ISO code from Accept-Language header
func parseAcceptLanguage(header string) string {
	// Split by comma
	parts := strings.Split(header, ",")
	if len(parts) == 0 {
		return ""
	}

	// Get the first part (highest priority)
	first := strings.TrimSpace(parts[0])
	if first == "" {
		return ""
	}

	// Remove any quality value (e.g., ";q=0.9")
	if idx := strings.Index(first, ";"); idx != -1 {
		first = strings.TrimSpace(first[:idx])
	}

	// Handle cases like "en-US" or "en"
	// Return the primary language code (first part before dash)
	if idx := strings.Index(first, "-"); idx != -1 {
		return strings.ToLower(first[:idx])
	}

	return strings.ToLower(first)
}

// GetLanguageID extracts language ID from context
func GetLanguageID(c fiber.Ctx) uint {
	langID, ok := c.Locals("langID").(uint)
	if !ok {
		return 0
	}
	return langID
}
