// Copyright (c) 2024-2026 Tencent Zhuque Lab. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Requirement: Any integration or derivative work must explicitly attribute
// Tencent Zhuque Lab (https://github.com/Tencent/AI-Infra-Guard) in its
// documentation or user interface, as detailed in the NOTICE file.

// Package parser 实现了指纹规则的解析和评估功能。
// 该包提供了将YAML格式的指纹规则转换为可执行规则对象的功能，
// 并支持对HTTP请求响应进行指纹匹配评估。
package parser

import (
	"fmt"

	"gopkg.in/yaml.v2"
)

// FingerPrintInfo 定义了指纹的基本信息
type FingerPrintInfo struct {
	Name           string            `yaml:"name" json:"name"`
	Author         string            `yaml:"author" json:"author"`
	Example        []string          `yaml:"example,omitempty" json:"example,omitempty"`
	Desc           string            `yaml:"desc,omitempty" json:"desc,omitempty"`
	Severity       string            `yaml:"severity" json:"severity"`
	Metadata       map[string]string `yaml:"metadata" json:"metadata"`
	Recommendation int               `yaml:"recommendation,omitempty" json:"recommendation,omitempty"`
}

// Extractor 定义了从响应中提取信息的规则
type Extractor struct {
	Part  string `yaml:"part" json:"part"`
	Group string `yaml:"group" json:"group"`
	Regex string `yaml:"regex" json:"regex"`
}

// HttpRule 定义了HTTP请求匹配规则
type HttpRule struct {
	Method       string    `yaml:"method" json:"method"`
	Path         string    `yaml:"path" json:"path"`
	Matchers     []string  `yaml:"matchers" json:"matchers"`
	Data         string    `yaml:"data,omitempty" json:"data,omitempty"`
	dsl          []*Rule   `yaml:"-" json:"-"`
	VersionRange string    `yaml:"versionrange,omitempty" json:"versionrange,omitempty"`
	Extractor    Extractor `yaml:"extractor,omitempty" json:"extractor,omitempty"`
}

// GetDsl 返回解析后的DSL规则列表
func (h *HttpRule) GetDsl() []*Rule {
	return h.dsl
}

// FingerPrint 定义了完整的指纹规则结构
type FingerPrint struct {
	Info    FingerPrintInfo `yaml:"info" json:"info"`
	Http    []HttpRule      `yaml:"http" json:"http"`
	Version []HttpRule      `yaml:"version,omitempty" json:"version,omitempty"`
}

// FingerPrints 表示多个指纹规则的集合
type FingerPrints []FingerPrint

// Config 定义了进行指纹匹配时需要的配置信息
type Config struct {
	Body   string
	Header string
	Icon   int32
	Hash   string
}

// AdvisoryConfig 提供漏洞配置信息
type AdvisoryConfig struct {
	Version    string
	IsInternal bool
}

// transfromRule 将规则字符串转换为规则对象
// 参数:
//   - rule: 规则字符串
//
// 返回:
//   - *Rule: 解析后的规则对象
//   - error: 解析过程中的错误
func transfromRule(rule string) (*Rule, error) {
	tokens, err := ParseTokens(rule)
	if err != nil {
		return nil, err
	}
	if err = CheckBalance(tokens); err != nil {
		return nil, err
	}
	return TransFormExp(tokens)
}

// InitFingerPrintFromData 从字节数据初始化指纹配置
// 参数:
//   - reader: 包含YAML格式指纹配置的字节数据
//
// 返回:
//   - *FingerPrint: 解析后的指纹对象
//   - error: 解析过程中的错误
func InitFingerPrintFromData(reader []byte) (*FingerPrint, error) {
	var fp FingerPrint
	err := yaml.Unmarshal(reader, &fp)
	if err != nil {
		return nil, err
	}
	if err := compileMatchers(fp.Http); err != nil {
		return nil, err
	}
	if err := compileMatchers(fp.Version); err != nil {
		return nil, err
	}
	return &fp, err
}

// compileMatchers compiles textual matchers into executable DSL rules.
func compileMatchers(rules []HttpRule) error {
	for i := range rules {
		dsls := make([]*Rule, 0, len(rules[i].Matchers))
		hasHashMatcher := false
		hasNonHashMatcher := false
		for _, matcher := range rules[i].Matchers {
			dsl, err := transfromRule(matcher)
			if err != nil {
				return err
			}
			usesHash, hashOnly := dsl.hashUsage()
			if usesHash {
				if !hashOnly {
					return fmt.Errorf("hash matcher cannot be combined with other fields: %s %s -> %s", rules[i].Method, rules[i].Path, matcher)
				}
				hasHashMatcher = true
			} else {
				hasNonHashMatcher = true
			}
			dsls = append(dsls, dsl)
		}
		if hasHashMatcher && hasNonHashMatcher {
			return fmt.Errorf("hash matcher cannot coexist with other matcher types: %s %s", rules[i].Method, rules[i].Path)
		}
		rules[i].dsl = dsls
	}
	return nil
}

// FpResult 指纹结构体
type FpResult struct {
	Name    string `json:"name"`
	Version string `json:"version,omitempty"`
}

// Eval 评估配置是否匹配规则
// 参数:
//   - config: 配置对象，包含请求体、请求头和图标信息
//   - dsl: 要评估的规则对象
//
// 返回:
//   - bool: 是否匹配规则
func Eval(config *Config, dsl *Rule) bool {
	return dsl.Eval(config)
}
