package casbin

import (
	"strings"

	"github.com/tech/sendico/pkg/mlogger"
	"go.uber.org/zap"
)

// CasbinZapLogger wraps a zap.Logger to implement Casbin's Logger interface.
type CasbinZapLogger struct {
	logger mlogger.Logger
}

// NewCasbinLogger constructs a new CasbinZapLogger.
func NewCasbinLogger(logger mlogger.Logger) *CasbinZapLogger {
	return &CasbinZapLogger{
		logger: logger.Named("driver"),
	}
}

// EnableLog enables or disables logging.
func (l *CasbinZapLogger) EnableLog(_ bool) {
	// ignore
}

// IsEnabled returns whether logging is currently enabled.
func (l *CasbinZapLogger) IsEnabled() bool {
	return true
}

// LogModel is called by Casbin when loading model settings (you can customize if you want).
func (l *CasbinZapLogger) LogModel(m [][]string) {
	l.logger.Info("Model loaded", zap.Any("model", m))
}

func (l *CasbinZapLogger) LogPolicy(m map[string][][]string) {
	l.logger.Info("Policy loaded", zap.Int("entries", len(m)))
}

func (l *CasbinZapLogger) LogError(err error, msg ...string) {
	// If no custom message was passed, log a generic one
	if len(msg) == 0 {
		l.logger.Warn("Error occurred", zap.Error(err))
		return
	}

	// Otherwise, join any provided messages and include them
	l.logger.Warn(strings.Join(msg, " "), zap.Error(err))
}

// LogEnforce is called by Casbin to log each Enforce() call if logging is enabled.
func (l *CasbinZapLogger) LogEnforce(matcher string, request []any, result bool, explains [][]string) {
	l.logger.Debug("Enforcing policy...", zap.String("matcher", matcher), zap.Any("request", request),
		zap.Bool("result", result), zap.Any("explains", explains))
}

// LogRole is called by Casbin when role manager adds or deletes a role.
func (l *CasbinZapLogger) LogRole(roles []string) {
	l.logger.Debug("Changing roles...", zap.Strings("roles", roles))
}
