package mapping

import (
	"fmt"
	"math"
	"regexp"
	"sort"
	"strconv"
	"strings"

	"qctextbuilder/internal/domain"
)

type SemanticSlotTarget struct {
	Slot           string `json:"slot"`
	FieldPath      string `json:"fieldPath"`
	FieldKey       string `json:"fieldKey"`
	DisplayLabel   string `json:"displayLabel,omitempty"`
	WebsiteSection string `json:"websiteSection,omitempty"`
	BlockID        string `json:"blockId,omitempty"`
	Reason         string `json:"reason,omitempty"`
}

type SemanticSlotMapping struct {
	Targets []SemanticSlotTarget `json:"targets"`
	BySlot  map[string][]SemanticSlotTarget
}

var semanticBlockIDPattern = regexp.MustCompile(`(?i)(?:^|[_.])([mcr]\d{3,})(?:[_.]|$)`)
var semanticLooseBlockIDPattern = regexp.MustCompile(`(?i)([mcr]\d{3,})`)
var semanticIndexSuffixPattern = regexp.MustCompile(`_\d+$`)
var semanticTrailingNumberPattern = regexp.MustCompile(`_(\d+)$`)

func MapTemplateFieldsToSemanticSlots(fields []domain.TemplateField) SemanticSlotMapping {
	sectionGroupIndex := map[string]map[string]int{
		domain.WebsiteSectionServices:     {},
		domain.WebsiteSectionServiceItem:  {},
		domain.WebsiteSectionTeam:         {},
		domain.WebsiteSectionTestimonials: {},
	}
	sectionGroupNext := map[string]int{
		domain.WebsiteSectionServices:     0,
		domain.WebsiteSectionServiceItem:  0,
		domain.WebsiteSectionTeam:         0,
		domain.WebsiteSectionTestimonials: 0,
	}
	repeatedIndexResolver := newSemanticRepeatedIndexResolver(fields)

	targets := make([]SemanticSlotTarget, 0)
	for _, field := range fields {
		if !field.IsEnabled || !strings.EqualFold(strings.TrimSpace(field.FieldKind), "text") {
			continue
		}

		section := semanticSection(field)
		role := semanticRole(field)
		slot, mapped := semanticSlotForField(field, section, role, sectionGroupIndex, sectionGroupNext, repeatedIndexResolver)
		if !mapped {
			continue
		}

		reason := "section=" + section + ", role=" + role
		if blockID := semanticExtractBlockID(field); blockID != "" {
			reason += ", block=" + blockID
		}

		targets = append(targets, SemanticSlotTarget{
			Slot:           slot,
			FieldPath:      strings.TrimSpace(field.Path),
			FieldKey:       strings.TrimSpace(field.KeyName),
			DisplayLabel:   strings.TrimSpace(field.DisplayLabel),
			WebsiteSection: section,
			BlockID:        semanticExtractBlockID(field),
			Reason:         reason,
		})
	}

	sort.SliceStable(targets, func(i, j int) bool {
		if targets[i].Slot == targets[j].Slot {
			return targets[i].FieldPath < targets[j].FieldPath
		}
		return targets[i].Slot < targets[j].Slot
	})

	bySlot := make(map[string][]SemanticSlotTarget, len(targets))
	for _, target := range targets {
		bySlot[target.Slot] = append(bySlot[target.Slot], target)
	}
	return SemanticSlotMapping{
		Targets: targets,
		BySlot:  bySlot,
	}
}

func semanticSlotForField(
	field domain.TemplateField,
	section string,
	role string,
	sectionGroupIndex map[string]map[string]int,
	sectionGroupNext map[string]int,
	repeatedIndexResolver *semanticRepeatedIndexResolver,
) (string, bool) {
	switch section {
	case domain.WebsiteSectionHero:
		if role == "title" {
			return "hero.title", true
		}
	case domain.WebsiteSectionIntro:
		if role == "title" {
			return "intro.title", true
		}
		if role == "description" {
			return "intro.description", true
		}
	case domain.WebsiteSectionAbout:
		if role == "description" || role == "title" {
			return "about.description", true
		}
	case domain.WebsiteSectionServices, domain.WebsiteSectionServiceItem:
		if role == "title" || role == "description" {
			index := semanticRepeatedIndex(section, role, field, sectionGroupIndex, sectionGroupNext, repeatedIndexResolver)
			return fmt.Sprintf("service_items[%d].%s", index, role), true
		}
	case domain.WebsiteSectionTeam:
		if role == "name" || role == "description" {
			index := semanticRepeatedIndex(section, role, field, sectionGroupIndex, sectionGroupNext, repeatedIndexResolver)
			return fmt.Sprintf("team_items[%d].%s", index, role), true
		}
	case domain.WebsiteSectionTestimonials:
		if role == "title" || role == "description" || role == "name" {
			index := semanticRepeatedIndex(section, role, field, sectionGroupIndex, sectionGroupNext, repeatedIndexResolver)
			return fmt.Sprintf("testimonial_items[%d].%s", index, role), true
		}
	case domain.WebsiteSectionCTA:
		if role == "cta_text" || role == "title" || role == "description" {
			return "cta.text", true
		}
	}
	return "", false
}

func semanticRepeatedIndex(
	section string,
	role string,
	field domain.TemplateField,
	sectionGroupIndex map[string]map[string]int,
	sectionGroupNext map[string]int,
	repeatedIndexResolver *semanticRepeatedIndexResolver,
) int {
	if repeatedIndexResolver != nil {
		if idx, ok := repeatedIndexResolver.IndexFor(section, role, field); ok {
			return idx
		}
	}
	return semanticGroupIndex(section, field, sectionGroupIndex, sectionGroupNext)
}

func semanticGroupIndex(
	section string,
	field domain.TemplateField,
	sectionGroupIndex map[string]map[string]int,
	sectionGroupNext map[string]int,
) int {
	normalizedSection := domain.NormalizeWebsiteSection(section)
	group := semanticGroupKey(field)
	if _, ok := sectionGroupIndex[normalizedSection]; !ok {
		sectionGroupIndex[normalizedSection] = map[string]int{}
	}
	if idx, ok := sectionGroupIndex[normalizedSection][group]; ok {
		return idx
	}
	idx := sectionGroupNext[normalizedSection]
	sectionGroupNext[normalizedSection] = idx + 1
	sectionGroupIndex[normalizedSection][group] = idx
	return idx
}

func semanticGroupKey(field domain.TemplateField) string {
	if blockID := semanticExtractBlockID(field); blockID != "" {
		return "block:" + blockID
	}
	key := strings.ToLower(strings.TrimSpace(field.KeyName))
	if key != "" {
		return "key:" + semanticIndexSuffixPattern.ReplaceAllString(key, "")
	}
	path := strings.ToLower(strings.TrimSpace(field.Path))
	return "path:" + semanticIndexSuffixPattern.ReplaceAllString(path, "")
}

func semanticSection(field domain.TemplateField) string {
	websiteSection := domain.NormalizeWebsiteSection(field.WebsiteSection)
	if websiteSection != domain.WebsiteSectionOther {
		return websiteSection
	}
	return domain.SuggestWebsiteSection(field)
}

func semanticRole(field domain.TemplateField) string {
	parts := []string{
		strings.ToLower(strings.TrimSpace(field.KeyName)),
		strings.ToLower(strings.TrimSpace(field.Path)),
		strings.ToLower(strings.TrimSpace(field.DisplayLabel)),
		strings.ToLower(strings.TrimSpace(field.Section)),
	}
	combined := strings.Join(parts, " ")
	switch {
	case semanticContainsAny(combined, "description", "subtitle", "paragraph", "copy", "body", "content", "mission", "story", "bio", "quote"):
		return "description"
	case semanticContainsAny(combined, "button", "btn", "calltoaction", "call_to_action", "cta"):
		return "cta_text"
	case semanticContainsAny(combined, "headline", "heading", "title"):
		return "title"
	case semanticContainsAny(combined, "author", "customer", "person", "member", "name"):
		return "name"
	default:
		return "description"
	}
}

func semanticExtractBlockID(field domain.TemplateField) string {
	candidates := []string{
		strings.TrimSpace(field.KeyName),
		strings.TrimSpace(field.Path),
		strings.TrimSpace(field.DisplayLabel),
	}
	for _, candidate := range candidates {
		if candidate == "" {
			continue
		}
		if match := semanticBlockIDPattern.FindStringSubmatch(candidate); len(match) > 1 {
			return strings.ToLower(match[1])
		}
	}
	for _, candidate := range candidates {
		if candidate == "" {
			continue
		}
		if match := semanticLooseBlockIDPattern.FindStringSubmatch(candidate); len(match) > 1 {
			return strings.ToLower(match[1])
		}
	}
	return ""
}

func semanticContainsAny(value string, needles ...string) bool {
	for _, needle := range needles {
		if strings.Contains(value, needle) {
			return true
		}
	}
	return false
}

type semanticRepeatedIndexResolver struct {
	byFieldKey map[string]int
}

type semanticRepeatedField struct {
	fieldKey string
	suffix   int
	path     string
}

func newSemanticRepeatedIndexResolver(fields []domain.TemplateField) *semanticRepeatedIndexResolver {
	resolver := &semanticRepeatedIndexResolver{
		byFieldKey: map[string]int{},
	}
	// Pair repeated fields by section + block + role + numeric suffix ordering.
	buckets := map[string][]semanticRepeatedField{}
	for _, field := range fields {
		if !field.IsEnabled || !strings.EqualFold(strings.TrimSpace(field.FieldKind), "text") {
			continue
		}
		section := semanticSection(field)
		if !semanticIsRepeatedSection(section) {
			continue
		}
		role := semanticRole(field)
		if !semanticRoleAllowedForRepeated(section, role) {
			continue
		}
		suffix, ok := semanticTrailingNumber(field)
		if !ok {
			continue
		}
		bucket := semanticRepeatedBucketKey(section, semanticExtractBlockID(field), role)
		entry := semanticRepeatedField{
			fieldKey: semanticFieldIdentity(field),
			suffix:   suffix,
			path:     strings.TrimSpace(field.Path),
		}
		buckets[bucket] = append(buckets[bucket], entry)
	}

	for _, bucketEntries := range buckets {
		sort.SliceStable(bucketEntries, func(i, j int) bool {
			if bucketEntries[i].suffix != bucketEntries[j].suffix {
				return bucketEntries[i].suffix < bucketEntries[j].suffix
			}
			return bucketEntries[i].path < bucketEntries[j].path
		})
		for idx, entry := range bucketEntries {
			resolver.byFieldKey[entry.fieldKey] = idx
		}
	}
	return resolver
}

func (r *semanticRepeatedIndexResolver) IndexFor(section string, role string, field domain.TemplateField) (int, bool) {
	if r == nil || len(r.byFieldKey) == 0 {
		return 0, false
	}
	if !semanticIsRepeatedSection(section) || !semanticRoleAllowedForRepeated(section, role) {
		return 0, false
	}
	idx, ok := r.byFieldKey[semanticFieldIdentity(field)]
	return idx, ok
}

func semanticIsRepeatedSection(section string) bool {
	switch domain.NormalizeWebsiteSection(section) {
	case domain.WebsiteSectionServices, domain.WebsiteSectionServiceItem, domain.WebsiteSectionTeam, domain.WebsiteSectionTestimonials:
		return true
	default:
		return false
	}
}

func semanticRoleAllowedForRepeated(section string, role string) bool {
	switch domain.NormalizeWebsiteSection(section) {
	case domain.WebsiteSectionServices, domain.WebsiteSectionServiceItem:
		return role == "title" || role == "description"
	case domain.WebsiteSectionTeam:
		return role == "name" || role == "description"
	case domain.WebsiteSectionTestimonials:
		return role == "name" || role == "title" || role == "description"
	default:
		return false
	}
}

func semanticRepeatedBucketKey(section string, blockID string, role string) string {
	normalizedSection := domain.NormalizeWebsiteSection(section)
	if normalizedSection == domain.WebsiteSectionServiceItem {
		normalizedSection = domain.WebsiteSectionServices
	}
	block := strings.TrimSpace(strings.ToLower(blockID))
	if block == "" {
		block = "__no_block__"
	}
	return normalizedSection + "|" + block + "|" + role
}

func semanticTrailingNumber(field domain.TemplateField) (int, bool) {
	candidates := []string{
		strings.TrimSpace(strings.ToLower(field.Path)),
		strings.TrimSpace(strings.ToLower(field.KeyName)),
	}
	best := math.MaxInt
	found := false
	for _, candidate := range candidates {
		if candidate == "" {
			continue
		}
		match := semanticTrailingNumberPattern.FindStringSubmatch(candidate)
		if len(match) < 2 {
			continue
		}
		value, err := strconv.Atoi(match[1])
		if err != nil {
			continue
		}
		if value < best {
			best = value
		}
		found = true
	}
	if !found {
		return 0, false
	}
	return best, true
}

func semanticFieldIdentity(field domain.TemplateField) string {
	return strings.ToLower(strings.TrimSpace(field.Path)) + "|" + strings.ToLower(strings.TrimSpace(field.KeyName))
}
