package exec

import (
	"errors"
	"log/slog"
	"sync"
	"time"

	"github.com/tidbcloud/AgentTeam/desktop/internal/token"
)

const execAuthorizationWarningInterval = time.Minute

var execAuthorizationWarnings = struct {
	sync.Mutex
	last map[string]time.Time
}{last: make(map[string]time.Time)}

func logExecAuthorizationFailure(err error) {
	reason := execAuthorizationFailureReason(err)
	// Invalid format/signature is fully attacker-controlled. Other reasons are
	// useful operational signals, but emit at warning level at most once per
	// reason/minute. Every event remains available at debug level.
	if reason == "invalid_format" || reason == "invalid_signature" || !admitExecAuthorizationWarning(reason, time.Now()) {
		slog.Debug("agentteam exec authorization rejected", "reason", reason)
		return
	}
	if isKnownExecAuthorizationFailure(err) {
		slog.Warn("agentteam exec authorization rejected", "reason", reason)
		return
	}
	slog.Warn("agentteam exec authorization failed internally", "reason", reason)
}

func admitExecAuthorizationWarning(reason string, now time.Time) bool {
	execAuthorizationWarnings.Lock()
	defer execAuthorizationWarnings.Unlock()
	last := execAuthorizationWarnings.last[reason]
	if !last.IsZero() && now.Sub(last) < execAuthorizationWarningInterval {
		return false
	}
	execAuthorizationWarnings.last[reason] = now
	return true
}

func execAuthorizationFailureReason(err error) string {
	switch {
	case errors.Is(err, token.ErrExpired):
		return "expired"
	case errors.Is(err, token.ErrAgentTokenRevoked):
		return "revoked"
	case errors.Is(err, token.ErrAgentTokenInactive):
		return "inactive"
	case errors.Is(err, token.ErrAgentTokenServerMismatch):
		return "server_mismatch"
	case errors.Is(err, token.ErrAgentTokenScopeMismatch):
		return "scope_mismatch"
	case errors.Is(err, token.ErrAgentMismatch):
		return "agent_mismatch"
	case errors.Is(err, token.ErrInvalidSignature):
		return "invalid_signature"
	case errors.Is(err, token.ErrInvalidFormat):
		return "invalid_format"
	default:
		return "internal"
	}
}

func isKnownExecAuthorizationFailure(err error) bool {
	return errors.Is(err, token.ErrExpired) ||
		errors.Is(err, token.ErrAgentTokenRevoked) ||
		errors.Is(err, token.ErrAgentTokenInactive) ||
		errors.Is(err, token.ErrAgentTokenServerMismatch) ||
		errors.Is(err, token.ErrAgentTokenScopeMismatch) ||
		errors.Is(err, token.ErrAgentMismatch) ||
		errors.Is(err, token.ErrInvalidSignature) ||
		errors.Is(err, token.ErrInvalidFormat)
}
