package linedb

import "strings"

type stringMatchMode int

const (
	stringMatchEqual stringMatchMode = iota
	stringMatchContains
	stringMatchHasPrefix
	stringMatchHasSuffix
)

func matchStringByPattern(value string, pattern string, strictCompare bool) bool {
	mode, lit := parsePercentPattern(pattern)

	if !strictCompare {
		// For substring checks we use ToLower (close enough to EqualFold intent).
		value = strings.ToLower(value)
		lit = strings.ToLower(lit)
	}

	switch mode {
	case stringMatchContains:
		return strings.Contains(value, lit)
	case stringMatchHasPrefix:
		return strings.HasPrefix(value, lit)
	case stringMatchHasSuffix:
		return strings.HasSuffix(value, lit)
	default:
		if strictCompare {
			return value == lit
		}
		return strings.EqualFold(value, lit)
	}
}

// parsePercentPattern interprets unescaped % at the start/end of pattern:
// - %foo% => contains "foo"
// - foo%  => hasPrefix "foo"
// - %foo  => hasSuffix "foo"
// - foo   => equal "foo"
// Escaping: \% means literal %, \\ means literal \ (only affects escape processing).
func parsePercentPattern(pattern string) (stringMatchMode, string) {
	if pattern == "" {
		return stringMatchEqual, ""
	}

	leading := pattern[0] == '%'
	trailing := len(pattern) > 0 && pattern[len(pattern)-1] == '%' && !isEscapedAt(pattern, len(pattern)-1)

	start := 0
	end := len(pattern)
	if leading {
		start = 1
	}
	if trailing && end > start {
		end--
	}
	lit := unescapePercents(pattern[start:end])

	switch {
	case leading && trailing:
		return stringMatchContains, lit
	case trailing:
		return stringMatchHasPrefix, lit
	case leading:
		return stringMatchHasSuffix, lit
	default:
		return stringMatchEqual, unescapePercents(pattern)
	}
}

func isEscapedAt(s string, idx int) bool {
	// idx is escaped if preceded by an odd number of backslashes.
	if idx <= 0 || idx >= len(s) {
		return false
	}
	n := 0
	for i := idx - 1; i >= 0 && s[i] == '\\'; i-- {
		n++
	}
	return n%2 == 1
}

func unescapePercents(s string) string {
	if s == "" {
		return ""
	}
	var b strings.Builder
	b.Grow(len(s))
	esc := false
	for i := 0; i < len(s); i++ {
		ch := s[i]
		if esc {
			// Only unescape % and \; keep backslash for other chars.
			if ch == '%' || ch == '\\' {
				b.WriteByte(ch)
			} else {
				b.WriteByte('\\')
				b.WriteByte(ch)
			}
			esc = false
			continue
		}
		if ch == '\\' {
			esc = true
			continue
		}
		b.WriteByte(ch)
	}
	if esc {
		// dangling backslash
		b.WriteByte('\\')
	}
	return b.String()
}

