// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.

// Symbol.go
package scan

import (
	"strings"
)

var symbolMap map[Symbol]symbolSpec

type SymbolClass int16

const (
	SymClassOperator SymbolClass = iota
	SymClassCommand
	SymClassIdentifier
	SymClassDelimiter
	SymClassParenthesis
	SymClassDeclaration
	SymClassValue
	SymClassOther
)

type symbolSpec struct {
	repr   string
	kind   SymbolClass
	opType TermPosition
}

func init() {

	symbolMap = map[Symbol]symbolSpec{
		SymUnknown:            {"<unknown>", SymClassOther, PosLeaf},  //  -1: Unknown symbol
		SymNone:               {"<null>", SymClassOther, PosLeaf},     //   0: Null value for variable of type symbol
		SymError:              {"<error>", SymClassOther, PosLeaf},    //   1: Error reading from stream
		SymEos:                {"<eos>", SymClassOther, PosLeaf},      //   2: End of stream
		SymMinus:              {"-", SymClassOperator, PosInfix},      //   3: '-'
		SymMinusEqual:         {"-=", SymClassOperator, PosInfix},     //   4: '-='
		SymDoubleMinus:        {"--", SymClassOperator, PosPostfix},   //   5: '--'
		SymPlus:               {"+", SymClassOperator, PosInfix},      //   6: '+'
		SymPlusEqual:          {"+=", SymClassOperator, PosInfix},     //   7: '+='
		SymDoublePlus:         {"++", SymClassOperator, PosPostfix},   //   8: '++'
		SymStar:               {"*", SymClassOperator, PosInfix},      //   9: '*'
		SymDoubleStar:         {"**", SymClassOperator, PosInfix},     //  10: '**'
		SymSlash:              {"/", SymClassOperator, PosInfix},      //  11: '/'
		SymBackSlash:          {"\\", SymClassOperator, PosLeaf},      //  12: '\'
		SymVertBar:            {"|", SymClassOperator, PosInfix},      //  13: '|'
		SymDoubleVertBar:      {"||", SymClassOperator, PosInfix},     //  14: '||'
		SymComma:              {",", SymClassOperator, PosInfix},      //  15: ','
		SymColon:              {":", SymClassOperator, PosInfix},      //  16: ':'
		SymSemiColon:          {";", SymClassOperator, PosInfix},      //  17: ';'
		SymDot:                {".", SymClassOperator, PosInfix},      //  18: '.'
		SymDotSlash:           {"./", SymClassOperator, PosInfix},     //  19: './'
		SymQuote:              {"'", SymClassDelimiter, PosLeaf},      //  20: '\''
		SymDoubleQuote:        {"\"", SymClassDelimiter, PosLeaf},     //  21: '"'
		SymBackTick:           {"`", SymClassDelimiter, PosLeaf},      //  22: '`'
		SymExclamation:        {"!", SymClassOperator, PosPostfix},    //  23: '!'
		SymQuestion:           {"?", SymClassOperator, PosInfix},      //  24: '?'
		SymAmpersand:          {"&", SymClassOperator, PosInfix},      //  25: '&'
		SymDoubleAmpersand:    {"&&", SymClassOperator, PosInfix},     //  26: '&&'
		SymPercent:            {"%", SymClassOperator, PosInfix},      //  27: '%'
		SymAt:                 {"@", SymClassOperator, PosPrefix},     //  28: '@'
		SymUndescore:          {"_", SymClassIdentifier, PosLeaf},     //  29: '_'
		SymEqual:              {"=", SymClassOperator, PosInfix},      //  30: '='
		SymDoubleEqual:        {"==", SymClassOperator, PosInfix},     //  31: '=='
		SymLess:               {"<", SymClassOperator, PosInfix},      //  32: '<'
		SymLessOrEqual:        {"<=", SymClassOperator, PosInfix},     //  33: '<='
		SymGreater:            {">", SymClassOperator, PosInfix},      //  34: '>'
		SymGreaterOrEqual:     {">=", SymClassOperator, PosInfix},     //  35: '>='
		SymLessGreater:        {"<>", SymClassOperator, PosInfix},     //  36: '<>'
		SymNotEqual:           {"!=", SymClassOperator, PosInfix},     //  37: '!='
		SymDollar:             {"$", SymClassOperator, PosPrefix},     //  38: '$'
		SymHash:               {"#", SymClassOperator, PosPrefix},     //  39: '#'
		SymOpenRound:          {"(", SymClassParenthesis, PosPrefix},  //  40: '('
		SymClosedRound:        {")", SymClassParenthesis, PosPostfix}, //  41: ')'
		SymOpenSquare:         {"[", SymClassParenthesis, PosPrefix},  //  42: '['
		SymClosedSquare:       {"]", SymClassParenthesis, PosPostfix}, //  43: ']'
		SymOpenBrace:          {"{", SymClassParenthesis, PosPrefix},  //  44: '{'
		SymClosedBrace:        {"}", SymClassParenthesis, PosPostfix}, //  45: '}'
		SymTilde:              {"~", SymClassOperator, PosPrefix},     //  46: '~'
		SymDoubleQuestion:     {"??", SymClassOperator, PosInfix},     //  47: '??'
		SymQuestionEqual:      {"?=", SymClassOperator, PosInfix},     //  48: '?='
		SymQuestionExclam:     {"?!", SymClassOperator, PosInfix},     //  49: '?!'
		SymDoubleAt:           {"@@", SymClassCommand, PosLeaf},       //  50: '@@'
		SymDoubleColon:        {"::", SymClassOperator, PosInfix},     //  51: '::'
		SymDoubleGreater:      {">>", SymClassOperator, PosInfix},     //  52: '>>'
		SymDoubleLess:         {"<<", SymClassOperator, PosInfix},     //  53: '<<'
		SymCaret:              {"^", SymClassOperator, PosInfix},      //  54: '^'
		SymDollarRound:        {"$(", SymClassOperator, PosPrefix},    //  55: '$('
		SymOpenClosedRound:    {"()", SymClassOperator, PosPostfix},   //  56: '()'
		SymDoubleDollar:       {"$$", SymClassCommand, PosLeaf},       //  57: '$$'
		SymDoubleDot:          {"..", SymClassOperator, PosInfix},     //  58: '..'
		SymTripleDot:          {"...", SymClassOperator, PosPostfix},  //  59: '...'
		SymStarEqual:          {"*=", SymClassOperator, PosInfix},     //  60: '*='
		SymSlashEqual:         {"/=", SymClassOperator, PosInfix},     //  61: '/='
		SymPercEqual:          {"%=", SymClassOperator, PosInfix},     //  62: '%='
		SymDoubleLessEqual:    {"<<=", SymClassOperator, PosInfix},    //  63: '<<='
		SymDoubleGreaterEqual: {">>=", SymClassOperator, PosInfix},    //  64: '>>='
		SymAmpersandEqual:     {"&=", SymClassOperator, PosInfix},     //  65: '&='
		SymVertBarEqual:       {"|=", SymClassOperator, PosInfix},     //  65: '|='
		SymCaretEqual:         {"^=", SymClassOperator, PosInfix},     //  66: '^='
		SymPlusGreater:        {"+>", SymClassOperator, PosInfix},     //  67: '+>'
		SymLessPlus:           {"<+", SymClassOperator, PosInfix},     //  68: '<+'
		SymPreInc:             {"++", SymClassOperator, PosPrefix},    //    : '++'
		SymPreDec:             {"--", SymClassOperator, PosPrefix},    //    : '--'
		// SymChangeSign
		// SymUnchangeSign
		// SymIdentifier
		// SymBool
		// SymInteger
		// SymVariable
		// SymFloat
		// SymFraction
		// SymString
		// SymIterator
		// SymOr:  "or",
		// SymAnd: "and",
		// SymNot: "not",
		// SymComment
		// SymFuncCall
		// SymFuncDef
		// SymList
		// SymDict
		// SymIndex
		// SymExpression
		// SymSelector     // <selector> ::= <expr> "?" <selector-case> {":" <selector-case>} ["::" <default-selector-case>]
		// SymSelectorCase // <selector-case> ::= [<list>] "{" <multi-expr> "}"
		// // SymOpenComment                       //   0: '/*'
		// // SymClosedComment                     //   0: '*/'
		// // SymOneLineComment                    //   0: '//'
		// keywordBase
		SymKwAnd:     {"and", SymClassOperator, PosInfix},
		SymKwNot:     {"not", SymClassOperator, PosInfix},
		SymKwOr:      {"or", SymClassOperator, PosInfix},
		SymKwBut:     {"but", SymClassOperator, PosInfix},
		SymKwMap:     {"map", SymClassOperator, PosInfix},
		SymKwFilter:  {"filter", SymClassOperator, PosInfix},
		SymKwDigest:  {"digest", SymClassOperator, PosInfix},
		SymKwJoin:    {"join", SymClassOperator, PosInfix},
		SymKwGroupBy: {"groupby", SymClassOperator, PosInfix},
		SymKwFunc:    {"func(", SymClassDeclaration, PosPrefix},
		SymKwBuiltin: {"builtin", SymClassOperator, PosPrefix},
		SymKwPlugin:  {"plugin", SymClassOperator, PosPrefix},
		SymKwIn:      {"in", SymClassOperator, PosInfix},
		SymKwInclude: {"include", SymClassOperator, PosPrefix},
		SymKwNil:     {"nil", SymClassValue, PosLeaf},
		SymKwUnset:   {"unset", SymClassOperator, PosPrefix},
	}
}

func SymToString(sym Symbol) string {
	if s, ok := symbolMap[sym]; ok {
		return s.repr
	}
	return ""
}

func SymListToString(symList []Symbol, quote bool) string {
	var sb strings.Builder
	if len(symList) == 0 {
		sb.WriteString("<nothing>")
	} else {
		for _, sym := range symList {
			if sb.Len() > 0 {
				sb.WriteByte(',')
				sb.WriteByte(' ')
			}
			if quote {
				sb.WriteByte('`')
			}
			sb.WriteString(SymToString(sym))
			if quote {
				sb.WriteByte('`')
			}
		}
	}
	return sb.String()
}

func StringEndsWithOperator(s string) bool {
	return endingOperator(s) != SymNone
}

// func endingOperator(s string) (sym Symbol) {
// 	var matchLength = 0
// 	sym = SymNone
// 	lower := strings.TrimRight(strings.ToLower(s), " \t")
// 	for symbol, spec := range symbolMap {
// 		if strings.HasSuffix(lower, spec.repr) {
// 			if len(spec.repr) > matchLength {
// 				matchLength = len(spec.repr)
// 				if spec.kind == symClassOperator && (spec.opType == PosInfix || spec.opType == PosPrefix) {
// 					sym = symbol
// 				} else {
// 					sym = SymNone
// 				}
// 			}
// 		}
// 	}
// 	return
// }

func endingOperator(s string) (sym Symbol) {
	var matchLength = 0
	var repr string
	sym = SymNone
	lower := strings.TrimRight(strings.ToLower(s), " \t")
	for symbol, spec := range symbolMap {
		if len(spec.repr) > matchLength || repr == spec.repr {
			if strings.HasSuffix(lower, spec.repr) {
				if isNotEndingSymbol(spec) && repr != spec.repr {
					repr = spec.repr
					matchLength = len(spec.repr)
					sym = symbol
				} else {
					sym = SymNone
					break
					// matchLength = 0
				}
			}
		}
	}
	return
}

func isNotEndingSymbol(spec symbolSpec) bool {
	return (spec.kind == SymClassOperator && (spec.opType == PosInfix || spec.opType == PosPrefix)) ||
		(spec.kind == SymClassParenthesis && spec.opType == PosPrefix)
}
