package searchservice

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"

	attributerepo "git.ma-al.com/goc_daniel/b2b/app/repos/attributeRepo"
	categoryrepo "git.ma-al.com/goc_daniel/b2b/app/repos/categoryRepo"
	featurerepo "git.ma-al.com/goc_daniel/b2b/app/repos/featureRepo"
	searchrepo "git.ma-al.com/goc_daniel/b2b/app/repos/searchRepo"
)

type SearchService struct {
	searchRepo    searchrepo.UISearchRepo
	attributeRepo attributerepo.UIAttributeRepo
	featureRepo   featurerepo.UIFeatureRepo
	categoryRepo  categoryrepo.UICategoryRepo
}

func New() *SearchService {
	return &SearchService{
		searchRepo:    searchrepo.New(),
		attributeRepo: attributerepo.New(),
		featureRepo:   featurerepo.New(),
		categoryRepo:  categoryrepo.New(),
	}
}

func (s *SearchService) Search(index string, body []byte, idLang uint) (*searchrepo.SearchProxyResponse, error) {
	resp, err := s.searchRepo.Search(index, body)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode == 200 {
		var data map[string]interface{}
		if err := json.Unmarshal(resp.Body, &data); err == nil {
			data = s.filterEmptyFacets(data)
			data = s.enrichFacetTranslations(data, idLang)
			resp.Body, _ = json.Marshal(data)
		}
	}

	return resp, nil
}

func (s *SearchService) GetIndexSettings(index string) (*searchrepo.SearchProxyResponse, error) {
	return s.searchRepo.GetIndexSettings(index)
}

func (s *SearchService) IsIndexNotFound(body []byte) bool {
	var resp map[string]interface{}
	if err := json.Unmarshal(body, &resp); err != nil {
		return false
	}
	if code, ok := resp["code"].(string); ok {
		return code == "index_not_found"
	}
	return false
}

func (s *SearchService) filterEmptyFacets(data map[string]interface{}) map[string]interface{} {
	if facets, ok := data["facetDistribution"].(map[string]interface{}); ok {
		filtered := make(map[string]interface{})
		for k, v := range facets {
			if m, ok := v.(map[string]interface{}); ok && len(m) > 0 {
				filtered[k] = v
			}
		}
		data["facetDistribution"] = filtered
	}
	return data
}

func (s *SearchService) enrichFacetTranslations(data map[string]interface{}, idLang uint) map[string]interface{} {
	facets, ok := data["facetDistribution"].(map[string]interface{})
	if !ok {
		return data
	}

	groupIDs := []uint{}
	attrIDs := []uint{}

	featureIDs := []uint{}
	featureValueIDs := []uint{}

	categoryIDs := []uint{}

	for key, values := range facets {
		valueMap, ok := values.(map[string]interface{})
		if !ok {
			continue
		}

		if strings.HasPrefix(key, "attr.") {
			groupIDStr := strings.TrimPrefix(key, "attr.")
			groupID, err := strconv.ParseUint(groupIDStr, 10, 64)
			if err != nil {
				continue
			}
			groupIDs = append(groupIDs, uint(groupID))

			for attrKey := range valueMap {
				attrID, err := strconv.ParseUint(attrKey, 10, 64)
				if err != nil {
					continue
				}
				attrIDs = append(attrIDs, uint(attrID))
			}
		}

		if strings.HasPrefix(key, "feat.") {
			featureIDStr := strings.TrimPrefix(key, "feat.")
			featureID, err := strconv.ParseUint(featureIDStr, 10, 64)
			if err != nil {
				continue
			}
			featureIDs = append(featureIDs, uint(featureID))

			for valueKey := range valueMap {
				valueID, err := strconv.ParseUint(valueKey, 10, 64)
				if err != nil {
					continue
				}
				featureValueIDs = append(featureValueIDs, uint(valueID))
			}
		}

		if key == "category_ids" {
			for catKey := range valueMap {
				catID, err := strconv.ParseUint(catKey, 10, 64)
				if err != nil {
					continue
				}
				categoryIDs = append(categoryIDs, uint(catID))
			}
		}
	}

	attributeGroups, _ := s.attributeRepo.GetAttributeGroupsWithAttributes(groupIDs, attrIDs, idLang)
	featureGroups, _ := s.featureRepo.GetFeaturesWithValues(featureIDs, featureValueIDs, idLang)
	categoryTranslations, _ := s.categoryRepo.GetCategoryTranslations(categoryIDs, idLang)

	translations := make(map[string]interface{})

	for _, groupID := range groupIDs {
		key := fmt.Sprintf("attr.%d", groupID)
		group, ok := attributeGroups[groupID]
		if !ok {
			group = attributerepo.AttributeGroupWithAttrs{
				GroupName: key,
				Attrs:     make(map[uint]attributerepo.AttributeWithColor),
			}
		}

		valueTranslations := make(map[string]interface{})
		for attrID, attr := range group.Attrs {
			attrName := attr.Name
			if attrName == "" {
				attrName = strconv.FormatUint(uint64(attrID), 10)
			}
			entry := map[string]string{"t": attrName}
			if attr.Color != "" {
				entry["c"] = attr.Color
			}
			valueTranslations[strconv.FormatUint(uint64(attrID), 10)] = entry
		}

		groupName := group.GroupName
		if groupName == "" {
			groupName = key
		}

		translations[key] = map[string]interface{}{
			"groupName": groupName,
			"values":    valueTranslations,
		}
	}

	for _, featureID := range featureIDs {
		key := fmt.Sprintf("feat.%d", featureID)
		feature, ok := featureGroups[featureID]
		if !ok {
			feature = featurerepo.FeatureGroupWithValues{
				FeatureName: key,
				Values:      make(map[uint]string),
			}
		}

		valueTranslations := make(map[string]interface{})
		for valueID, valueName := range feature.Values {
			if valueName == "" {
				valueName = strconv.FormatUint(uint64(valueID), 10)
			}
			valueTranslations[strconv.FormatUint(uint64(valueID), 10)] = map[string]string{
				"t": valueName,
			}
		}

		featureName := feature.FeatureName
		if featureName == "" {
			featureName = key
		}

		translations[key] = map[string]interface{}{
			"groupName": featureName,
			"values":    valueTranslations,
		}
	}

	categoryValueTranslations := make(map[string]interface{})
	for _, catID := range categoryIDs {
		catName := categoryTranslations[catID]
		if catName == "" {
			catName = strconv.FormatUint(uint64(catID), 10)
		}
		categoryValueTranslations[strconv.FormatUint(uint64(catID), 10)] = map[string]string{
			"t": catName,
		}
	}

	if len(categoryValueTranslations) > 0 {
		translations["category_ids"] = map[string]interface{}{
			"groupName": "category_ids",
			"values":    categoryValueTranslations,
		}
	}

	data["facetTranslations"] = translations
	return data
}
