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

// symbol-map.go
package scan

import (
	"strings"

	"git.portale-stac.it/go-pkg/expr/sym"
)

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

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

func SymListToString(symList []sym.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) != sym.SymNone
}

func endingOperator(s string) (resultSym sym.Symbol) {
	var matchLength = 0
	var repr string
	resultSym = 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)
					resultSym = symbol
				} else {
					resultSym = 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)
}
