package skills

import (
	"sort"
	"strings"
)

// Match retorna las skills mas relevantes para una query dada.
// Implementacion inicial: keyword matching simple contra name + description.
// La query y las skills son procesadas en lowercase para matching case-insensitive.
//
// El scoring es basico:
// - Match exacto en name: 1.0
// - Match parcial en name: 0.8
// - Match en description: 0.6 * (palabras coincidentes / palabras totales)
// - Sin match: 0.0
//
// Retorna las skills ordenadas por confidence descendente.
func Match(query string, skills []SkillMeta) []SkillMatch {
	query = strings.ToLower(strings.TrimSpace(query))
	if query == "" {
		return nil
	}

	queryWords := strings.Fields(query)
	var matches []SkillMatch

	for _, skill := range skills {
		confidence := scoreSkill(queryWords, skill)
		if confidence > 0 {
			matches = append(matches, SkillMatch{
				Skill:      skill,
				Confidence: confidence,
			})
		}
	}

	sort.Sort(ByConfidence(matches))
	return matches
}

// scoreSkill calcula el score de relevancia de una skill para las palabras de query.
func scoreSkill(queryWords []string, skill SkillMeta) float64 {
	nameLower := strings.ToLower(skill.Name)
	descLower := strings.ToLower(skill.Description)

	// Match exacto en name
	queryStr := strings.Join(queryWords, " ")
	if nameLower == queryStr {
		return 1.0
	}

	// Match parcial en name (todas las palabras de query aparecen en name)
	nameMatches := 0
	for _, word := range queryWords {
		if strings.Contains(nameLower, word) {
			nameMatches++
		}
	}
	if nameMatches == len(queryWords) {
		return 0.8
	}

	// Match en description (contar palabras coincidentes)
	descWords := strings.Fields(descLower)
	descMatches := 0
	for _, qword := range queryWords {
		for _, dword := range descWords {
			if strings.Contains(dword, qword) || strings.Contains(qword, dword) {
				descMatches++
				break
			}
		}
	}

	if descMatches > 0 {
		ratio := float64(descMatches) / float64(len(queryWords))
		return 0.6 * ratio
	}

	return 0.0
}

// FilterByCategory retorna solo las skills que pertenecen a las categorias especificadas.
// Si categories esta vacio, retorna todas las skills sin filtrar.
func FilterByCategory(skills []SkillMeta, categories []string) []SkillMeta {
	if len(categories) == 0 {
		return skills
	}

	catSet := make(map[string]bool)
	for _, cat := range categories {
		catSet[strings.ToLower(cat)] = true
	}

	var filtered []SkillMeta
	for _, skill := range skills {
		if catSet[strings.ToLower(skill.Category)] {
			filtered = append(filtered, skill)
		}
	}
	return filtered
}
