package service

import (
	"github.com/1Panel-dev/1Panel/backend/app/dto"
	"github.com/1Panel-dev/1Panel/backend/utils/firewall"
	fireClient "github.com/1Panel-dev/1Panel/backend/utils/firewall/client"
	"github.com/jinzhu/copier"
)

type FirewallService struct{}

type IFirewallService interface {
	SearchWithPage(search dto.RuleSearch) (int64, interface{}, error)
	OperatePortRule(req dto.PortRuleOperate) error
	OperateAddressRule(req dto.AddrRuleOperate) error
}

func NewIFirewallService() IFirewallService {
	return &FirewallService{}
}

func (u *FirewallService) SearchWithPage(req dto.RuleSearch) (int64, interface{}, error) {
	var (
		datas     []fireClient.FireInfo
		backDatas []fireClient.FireInfo
	)
	client, err := firewall.NewFirewallClient()
	if err != nil {
		return 0, nil, err
	}
	if req.Type == "port" {
		ports, err := client.ListPort()
		if err != nil {
			return 0, nil, err
		}
		datas = ports
	} else {
		address, err := client.ListAddress()
		if err != nil {
			return 0, nil, err
		}
		datas = address
	}
	total, start, end := len(datas), (req.Page-1)*req.PageSize, req.Page*req.PageSize
	if start > total {
		backDatas = make([]fireClient.FireInfo, 0)
	} else {
		if end >= total {
			end = total
		}
		backDatas = datas[start:end]
	}

	return int64(total), backDatas, nil
}

func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate) error {
	client, err := firewall.NewFirewallClient()
	if err != nil {
		return err
	}
	if req.Protocol == "tcp/udp" {
		req.Protocol = "tcp"
		if err := u.createPort(client, req); err != nil {
			return err
		}
		req.Protocol = "udp"
	}
	if err := u.createPort(client, req); err != nil {
		return err
	}
	return client.Reload()
}

func (u *FirewallService) OperateAddressRule(req dto.AddrRuleOperate) error {
	client, err := firewall.NewFirewallClient()
	if err != nil {
		return err
	}

	var fireInfo fireClient.FireInfo
	if err := copier.Copy(&fireInfo, &req); err != nil {
		return err
	}
	if err := client.RichRules(fireInfo, req.Operation); err != nil {
		return err
	}
	return client.Reload()
}

func (u *FirewallService) createPort(client firewall.FirewallClient, req dto.PortRuleOperate) error {
	var fireInfo fireClient.FireInfo
	if err := copier.Copy(&fireInfo, &req); err != nil {
		return err
	}

	if len(fireInfo.Address) != 0 || fireInfo.Strategy == "drop" {
		return client.RichRules(fireInfo, req.Operation)
	}
	return client.Port(fireInfo, req.Operation)
}