package security

import (
	"net"

	"github.com/wormhole/wormhole/internal/cache"
	"github.com/wormhole/wormhole/internal/store"
)

type Service struct {
	cache *cache.Manager
	store *store.Store
}

func NewService(c *cache.Manager, st *store.Store) *Service {
	return &Service{cache: c, store: st}
}

func (s *Service) Allow(ip string, clientID uint, resourceType string, resourceID uint) bool {
	scopes := []cache.Scope{
		{Kind: "global", ResourceID: 0},
		{Kind: "client", ResourceID: clientID},
	}
	if resourceType == "host" || resourceType == "tunnel" {
		scopes = append(scopes, cache.Scope{Kind: resourceType, ResourceID: resourceID})
	}
	return s.cache.AllowIP(ip, scopes)
}

func (s *Service) BlockIP(ip, scope string, resourceID uint, remark string) error {
	rule := &store.IPRule{
		Scope:       scope,
		ResourceID:  resourceID,
		Type:        "deny",
		Pattern:     ip,
		PatternKind: "exact",
		Priority:    100,
		Remark:      remark,
	}
	if err := s.store.CreateIPRule(rule); err != nil {
		return err
	}
	return s.cache.ReloadIPRules(s.store)
}

func DetectPatternKind(pattern string) string {
	if _, _, err := net.ParseCIDR(pattern); err == nil {
		return "cidr"
	}
	if len(pattern) > 0 && (pattern[0] == '^' || pattern[len(pattern)-1] == '$' || containsMeta(pattern)) {
		return "regex"
	}
	return "exact"
}

func containsMeta(s string) bool {
	for _, c := range s {
		switch c {
		case '.', '*', '+', '?', '[', ']', '(', ')', '|', '\\':
			return true
		}
	}
	return false
}
