package util

import (
	"log"
	"os"
	"sync"

	json "github.com/json-iterator/go"
)

type IAccessControl interface {
	IsInWhitelist(key string) bool
	IsInBlacklist(key string) bool
	Init() error
	GetPath() string
}

type FilterList struct {
	WhiteArr  []string `json:"whitelist"`
	BlackArr  []string `json:"blacklist"`
	Path      string
	whitelist map[string]struct{}
	blacklist map[string]struct{}
	lock      sync.RWMutex
}

func NewFilterList(path string) *FilterList {
	return &FilterList{Path: path}
}
func (l *FilterList) GetPath() string {
	return l.Path
}

func (l *FilterList) Init() error {
	fData, err := os.ReadFile(l.Path)
	if err != nil {
		log.Println("FilterList read failed ", err, l.Path)
		return err
	}

	err = json.Unmarshal(fData, l)
	if err != nil {
		log.Println("FilterList json unmarshal failed ", err, l.Path, ByteSliceToString(fData))
		return err
	}

	l.lock.Lock()
	defer l.lock.Unlock()
	l.whitelist = make(map[string]struct{})
	for _, key := range l.WhiteArr {
		l.whitelist[key] = struct{}{}
	}

	l.blacklist = make(map[string]struct{})
	for _, key := range l.BlackArr {
		l.blacklist[key] = struct{}{}
	}

	return nil
}

func (l *FilterList) IsInWhitelist(key string) bool {
	l.lock.RLock()
	if l.whitelist == nil {
		l.lock.RUnlock()
		err := l.Init()
		if err != nil {
			return true
		}
		l.lock.RLock()
	}

	defer l.lock.RUnlock()

	if len(l.whitelist) == 0 {
		return true
	}

	if _, ok := l.whitelist[key]; ok {
		return true
	}
	return false
}

func (l *FilterList) IsInBlacklist(key string) bool {
	l.lock.RLock()
	if l.blacklist == nil {
		l.lock.RUnlock()
		err := l.Init()
		if err != nil {
			return true
		}
		l.lock.RLock()
	}

	defer l.lock.RUnlock()

	if len(l.blacklist) == 0 {
		return true
	}

	if _, ok := l.blacklist[key]; ok {
		return true
	}
	return false
}
