package checker

import (
	"fmt"

	"github.com/pingcap/enterprise-toolkit/tispector/config"
	"github.com/pingcap/enterprise-toolkit/tispector/util/logger"
)

const ruleClose = 1

type DbInjectionRuleStatus struct {
	Name  string `json:"name" gorm:"column:name"`
	Close int    `json:"close" gorm:"column:close"`
}

// RuleStatusDao 规则表的相关方法和规则状态的相关方法写在一起了
type RuleStatusDao interface {
	ListAllStatus() ([]DbInjectionRuleStatus, error)
	UpdateRuleStatus(ruleStatus *DbInjectionRuleStatus) error
	InitRuleTable() error
	UpdateRule(Rule config.RuleConf) error
	GetRuleByItem(Item string) (DbInjectionRule, error)
	ListAllRules() ([]DbInjectionRule, error)
}

var ruleStatusDao RuleStatusDao

// GetRuleByItem 从数据库中以Item获取规则
func GetRuleByItem(Item string) (DbInjectionRule, error) {
	rule, err := ruleStatusDao.GetRuleByItem(Item)
	return rule, err
}

// ListAllRules 从数据库中读取所有规则并返回
func ListAllRules() ([]DbInjectionRule, error) {
	rules, err := ruleStatusDao.ListAllRules()
	return rules, err
}

//InitRuleTable 以本地yml文件初始化数据库中规则
func InitRuleTable() error {
	return ruleStatusDao.InitRuleTable()
}

// UpdateRule 更新数据库中单条规则
func UpdateRule(Rule config.RuleConf) error {
	return ruleStatusDao.UpdateRule(Rule)
}

// 它会返回当前的规则切片内容
func ListRules() []Rule {
	return Rules
}

func updateCacheRuleStatus(name string, close bool) {
	for i, v := range Rules {
		if v.Name == name {
			Rules[i].Close = close
		}
	}
}

// DbInjectionRule 构造Gorm能够识别的一个结构体
type DbInjectionRule struct {
	// 规则代号
	Item string `yaml:"Item" gorm:"item" json:"Item" `
	// 规则名称
	Name string `yaml:"Name" gorm:"name" json:"Name"`
	// 规则摘要
	Summary string `yaml:"Summary" gorm:"summary" json:"Summary"`
	// 规则解释
	Content string `yaml:"Content" gorm:"content" json:"Content"`
	// 是否禁用
	Close int `yaml:"Close" gorm:"close" json:"Close"`
	// 规则告警等级
	Level int `yaml:"Level" gorm:"level" json:"Level"`
	// SQL示例
	Case string `yaml:"Case" gorm:"case" json:"Case"`
	// 建议所处SQL字符位置，默认0表示全局建议
	Position int `yaml:"Position" gorm:"position" json:"Position"`
	// 函数名
	Checkfunc string `yaml:"CheckFunc" gorm:"checkfunc" json:"CheckFunc"`
	// 阈值
	Threshold string `yaml:"Threshold" gorm:"threshold" json:"Threshold"`
}

func SetRuleStatusDao(impl RuleStatusDao) {
	ruleStatusDao = impl
}

func InitRuleStatus() {
	ruleStatuses, err := ruleStatusDao.ListAllStatus()
	if err != nil {
		logger.Errorf("init rules, set rule status err: %s", err.Error())
		return
	}

	for _, ruleStatus := range ruleStatuses {
		for idx := range Rules {
			if Rules[idx].Name == ruleStatus.Name && ruleStatus.Close == ruleClose {
				Rules[idx].Close = true
			}
		}
	}
}

// 暂时用不到
func UpdateRuleStatus(name, action string) (err error) {
	switch action {
	case "close":
		if err = ruleStatusDao.UpdateRuleStatus(&DbInjectionRuleStatus{Name: name, Close: 1}); err == nil {
			updateCacheRuleStatus(name, true)
		}
		return
	case "open":
		if err = ruleStatusDao.UpdateRuleStatus(&DbInjectionRuleStatus{Name: name, Close: 0}); err == nil {
			updateCacheRuleStatus(name, false)
		}
		return
	default:
		return fmt.Errorf("update rule status action not defind, action: %s", action)
	}
}
