package iplibrary

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
	"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
	"strconv"
	"sync"
)

var SharedActionManager = NewActionManager()

// ActionManager 动作管理器定义
type ActionManager struct {
	locker sync.Mutex

	eventMap    map[string][]ActionInterface                    // eventLevel => []instance
	configMap   map[int64]*firewallconfigs.FirewallActionConfig // id => config
	instanceMap map[int64]ActionInterface                       // id => instance
}

// NewActionManager 获取动作管理对象
func NewActionManager() *ActionManager {
	return &ActionManager{
		configMap:   map[int64]*firewallconfigs.FirewallActionConfig{},
		instanceMap: map[int64]ActionInterface{},
	}
}

// UpdateActions 更新配置
func (this *ActionManager) UpdateActions(actions []*firewallconfigs.FirewallActionConfig) {
	this.locker.Lock()
	defer this.locker.Unlock()

	// 关闭不存在的
	newActionsMap := map[int64]*firewallconfigs.FirewallActionConfig{}
	for _, action := range actions {
		newActionsMap[action.Id] = action
	}
	for _, oldAction := range this.configMap {
		_, ok := newActionsMap[oldAction.Id]
		if !ok {
			instance, ok := this.instanceMap[oldAction.Id]
			if ok {
				_ = instance.Close()
				delete(this.instanceMap, oldAction.Id)
				remotelogs.Println("IPLIBRARY/ACTION_MANAGER", "close action "+strconv.FormatInt(oldAction.Id, 10))
			}
		}
	}

	// 添加新的或者更新老的
	for _, newAction := range newActionsMap {
		oldInstance, ok := this.instanceMap[newAction.Id]
		if ok {
			// 检查配置是否一致
			oldConfigJSON, err := json.Marshal(this.configMap[newAction.Id])
			if err != nil {
				remotelogs.Error("IPLIBRARY/ACTION_MANAGER", "action "+strconv.FormatInt(newAction.Id, 10)+", type:"+newAction.Type+": "+err.Error())
				continue
			}
			newConfigJSON, err := json.Marshal(newAction)
			if err != nil {
				remotelogs.Error("IPLIBRARY/ACTION_MANAGER", "action "+strconv.FormatInt(newAction.Id, 10)+", type:"+newAction.Type+": "+err.Error())
				continue
			}
			if !bytes.Equal(newConfigJSON, oldConfigJSON) {
				_ = oldInstance.Close()

				// 重新创建
				// 之所以要重新创建，是因为前后的动作类型可能有变化，完全重建可以避免不必要的麻烦
				newInstance, err := this.createInstance(newAction)
				if err != nil {
					remotelogs.Error("IPLIBRARY/ACTION_MANAGER", "reload action "+strconv.FormatInt(newAction.Id, 10)+", type:"+newAction.Type+": "+err.Error())
					continue
				}
				remotelogs.Println("IPLIBRARY/ACTION_MANAGER", "reloaded "+strconv.FormatInt(newAction.Id, 10)+", type:"+newAction.Type)
				this.instanceMap[newAction.Id] = newInstance
			}
		} else {
			// 创建
			instance, err := this.createInstance(newAction)
			if err != nil {
				remotelogs.Error("IPLIBRARY/ACTION_MANAGER", "load new action "+strconv.FormatInt(newAction.Id, 10)+", type:"+newAction.Type+": "+err.Error())
				continue
			}
			remotelogs.Println("IPLIBRARY/ACTION_MANAGER", "loaded action "+strconv.FormatInt(newAction.Id, 10)+", type:"+newAction.Type)
			this.instanceMap[newAction.Id] = instance
		}
	}

	// 更新配置
	this.configMap = newActionsMap
	this.eventMap = map[string][]ActionInterface{}
	for _, action := range this.configMap {
		instance, ok := this.instanceMap[action.Id]
		if !ok {
			continue
		}

		instances, _ := this.eventMap[action.EventLevel]
		instances = append(instances, instance)
		this.eventMap[action.EventLevel] = instances
	}
}

// FindEventActions 查找事件对应的动作
func (this *ActionManager) FindEventActions(eventLevel string) []ActionInterface {
	this.locker.Lock()
	defer this.locker.Unlock()
	return this.eventMap[eventLevel]
}

// AddItem 执行添加IP动作
func (this *ActionManager) AddItem(listType IPListType, item *pb.IPItem) {
	instances, ok := this.eventMap[item.EventLevel]
	if ok {
		for _, instance := range instances {
			err := instance.AddItem(listType, item)
			if err != nil {
				remotelogs.Error("IPLIBRARY/ACTION_MANAGER", "add item '"+fmt.Sprintf("%d", item.Id)+"': "+err.Error())
			}
		}
	}
}

// DeleteItem 执行删除IP动作
func (this *ActionManager) DeleteItem(listType IPListType, item *pb.IPItem) {
	instances, ok := this.eventMap[item.EventLevel]
	if ok {
		for _, instance := range instances {
			err := instance.DeleteItem(listType, item)
			if err != nil {
				remotelogs.Error("IPLIBRARY/ACTION_MANAGER", "delete item '"+fmt.Sprintf("%d", item.Id)+"': "+err.Error())
			}
		}
	}
}

func (this *ActionManager) createInstance(config *firewallconfigs.FirewallActionConfig) (ActionInterface, error) {
	var instance ActionInterface
	switch config.Type {
	case firewallconfigs.FirewallActionTypeIPSet:
		instance = NewIPSetAction()
	case firewallconfigs.FirewallActionTypeFirewalld:
		instance = NewFirewalldAction()
	case firewallconfigs.FirewallActionTypeIPTables:
		instance = NewIPTablesAction()
	case firewallconfigs.FirewallActionTypeScript:
		instance = NewScriptAction()
	case firewallconfigs.FirewallActionTypeHTTPAPI:
		instance = NewHTTPAPIAction()
	case firewallconfigs.FirewallActionTypeHTML:
		instance = NewHTMLAction()
	}
	if instance == nil {
		return nil, errors.New("can not create instance for type '" + config.Type + "'")
	}
	err := instance.Init(config)
	if err != nil {
		// 如果是警告错误，我们只是提示
		if !IsFatalError(err) {
			remotelogs.Error("IPLIBRARY/ACTION_MANAGER/CREATE_INSTANCE", "init '"+config.Type+"' failed: "+err.Error())
		} else {
			return nil, err
		}
	}
	return instance, nil
}
