package pgx

import (
	
	
	
	
)

// NamedArgs can be used as the first argument to a query method. It will replace every '@' named placeholder with a '$'
// ordinal placeholder and construct the appropriate arguments.
//
// For example, the following two queries are equivalent:
//
//	conn.Query(ctx, "select * from widgets where foo = @foo and bar = @bar", pgx.NamedArgs{"foo": 1, "bar": 2})
//	conn.Query(ctx, "select * from widgets where foo = $1 and bar = $2", 1, 2)
type NamedArgs map[string]any

// RewriteQuery implements the QueryRewriter interface.
func ( NamedArgs) ( context.Context,  *Conn,  string,  []any) ( string,  []any,  error) {
	 := &sqlLexer{
		src:           ,
		stateFn:       rawState,
		nameToOrdinal: make(map[namedArg]int, len()),
	}

	for .stateFn != nil {
		.stateFn = .stateFn()
	}

	 := strings.Builder{}
	for ,  := range .parts {
		switch p := .(type) {
		case string:
			.WriteString()
		case namedArg:
			.WriteRune('$')
			.WriteString(strconv.Itoa(.nameToOrdinal[]))
		}
	}

	 = make([]any, len(.nameToOrdinal))
	for ,  := range .nameToOrdinal {
		[-1] = [string()]
	}

	return .String(), , nil
}

type namedArg string

type sqlLexer struct {
	src     string
	start   int
	pos     int
	nested  int // multiline comment nesting level.
	stateFn stateFn
	parts   []any

	nameToOrdinal map[namedArg]int
}

type stateFn func(*sqlLexer) stateFn

func rawState( *sqlLexer) stateFn {
	for {
		,  := utf8.DecodeRuneInString(.src[.pos:])
		.pos += 

		switch  {
		case 'e', 'E':
			,  := utf8.DecodeRuneInString(.src[.pos:])
			if  == '\'' {
				.pos += 
				return escapeStringState
			}
		case '\'':
			return singleQuoteState
		case '"':
			return doubleQuoteState
		case '@':
			,  := utf8.DecodeRuneInString(.src[.pos:])
			if isLetter() {
				if .pos-.start > 0 {
					.parts = append(.parts, .src[.start:.pos-])
				}
				.start = .pos
				return namedArgState
			}
		case '-':
			,  := utf8.DecodeRuneInString(.src[.pos:])
			if  == '-' {
				.pos += 
				return oneLineCommentState
			}
		case '/':
			,  := utf8.DecodeRuneInString(.src[.pos:])
			if  == '*' {
				.pos += 
				return multilineCommentState
			}
		case utf8.RuneError:
			if .pos-.start > 0 {
				.parts = append(.parts, .src[.start:.pos])
				.start = .pos
			}
			return nil
		}
	}
}

func isLetter( rune) bool {
	return ( >= 'a' &&  <= 'z') || ( >= 'A' &&  <= 'Z')
}

func namedArgState( *sqlLexer) stateFn {
	for {
		,  := utf8.DecodeRuneInString(.src[.pos:])
		.pos += 

		if  == utf8.RuneError {
			if .pos-.start > 0 {
				 := namedArg(.src[.start:.pos])
				if ,  := .nameToOrdinal[]; ! {
					.nameToOrdinal[] = len(.nameToOrdinal) + 1
				}
				.parts = append(.parts, )
				.start = .pos
			}
			return nil
		} else if !(isLetter() || ( >= '0' &&  <= '9') ||  == '_') {
			.pos -= 
			 := namedArg(.src[.start:.pos])
			if ,  := .nameToOrdinal[]; ! {
				.nameToOrdinal[] = len(.nameToOrdinal) + 1
			}
			.parts = append(.parts, namedArg())
			.start = .pos
			return rawState
		}
	}
}

func singleQuoteState( *sqlLexer) stateFn {
	for {
		,  := utf8.DecodeRuneInString(.src[.pos:])
		.pos += 

		switch  {
		case '\'':
			,  := utf8.DecodeRuneInString(.src[.pos:])
			if  != '\'' {
				return rawState
			}
			.pos += 
		case utf8.RuneError:
			if .pos-.start > 0 {
				.parts = append(.parts, .src[.start:.pos])
				.start = .pos
			}
			return nil
		}
	}
}

func doubleQuoteState( *sqlLexer) stateFn {
	for {
		,  := utf8.DecodeRuneInString(.src[.pos:])
		.pos += 

		switch  {
		case '"':
			,  := utf8.DecodeRuneInString(.src[.pos:])
			if  != '"' {
				return rawState
			}
			.pos += 
		case utf8.RuneError:
			if .pos-.start > 0 {
				.parts = append(.parts, .src[.start:.pos])
				.start = .pos
			}
			return nil
		}
	}
}

func escapeStringState( *sqlLexer) stateFn {
	for {
		,  := utf8.DecodeRuneInString(.src[.pos:])
		.pos += 

		switch  {
		case '\\':
			_,  = utf8.DecodeRuneInString(.src[.pos:])
			.pos += 
		case '\'':
			,  := utf8.DecodeRuneInString(.src[.pos:])
			if  != '\'' {
				return rawState
			}
			.pos += 
		case utf8.RuneError:
			if .pos-.start > 0 {
				.parts = append(.parts, .src[.start:.pos])
				.start = .pos
			}
			return nil
		}
	}
}

func oneLineCommentState( *sqlLexer) stateFn {
	for {
		,  := utf8.DecodeRuneInString(.src[.pos:])
		.pos += 

		switch  {
		case '\\':
			_,  = utf8.DecodeRuneInString(.src[.pos:])
			.pos += 
		case '\n', '\r':
			return rawState
		case utf8.RuneError:
			if .pos-.start > 0 {
				.parts = append(.parts, .src[.start:.pos])
				.start = .pos
			}
			return nil
		}
	}
}

func multilineCommentState( *sqlLexer) stateFn {
	for {
		,  := utf8.DecodeRuneInString(.src[.pos:])
		.pos += 

		switch  {
		case '/':
			,  := utf8.DecodeRuneInString(.src[.pos:])
			if  == '*' {
				.pos += 
				.nested++
			}
		case '*':
			,  := utf8.DecodeRuneInString(.src[.pos:])
			if  != '/' {
				continue
			}

			.pos += 
			if .nested == 0 {
				return rawState
			}
			.nested--

		case utf8.RuneError:
			if .pos-.start > 0 {
				.parts = append(.parts, .src[.start:.pos])
				.start = .pos
			}
			return nil
		}
	}
}