package api

import "time"

// Valid responses from an enforcement rule.
const (
	EnforcementReject = "reject" // reject a message
	EnforcementOK     = "ok"     // accept the message if we don't have an explicit rejection
	EnforcementError  = "error"  // attempting to check this message resulted in an error
)

const (
	AutoModEnforcementName         = "channel_community_sift"
	BannedEnforcementName          = "banned"
	BlockedEnforcementName         = "blocked"
	DisposableEmailEnforcementName = "disposable_email"
	EmoteOnlyEnforcementName       = "emote_only"
	EntropyEnforcementName         = "entropy"
	FollowersOnlyEnforcementName   = "followers_only"
	SafeLinksEnforcementName       = "safe_links"
	SpamEnforcementName            = "spam"
	SubsOnlyEnforcementName        = "subs_only"
	SuspendedEnforcementName       = "suspended"
	VerifiedOnlyEnforcementName    = "verified_only"
	ZalgoEnforcementName           = "zalgo"
)

// EnforcementRuleset allows the user to specify which enforcement rules to run
type EnforcementRuleset struct {
	// AutoMod checks the message text against the containers AutoMod settings (TODO: if there is no container, default to AutoMod Lvl 1)
	AutoMod bool `json:"automod"`

	// Banned checks whether the sending user  is banned in the target container (skips if no container)
	Banned bool `json:"banned"`

	// Blocked checks whether the sending user is blocked in the target container (skips if no container)
	Blocked bool `json:"blocked"`

	//  DisposableEmail checks whether the sending user has a disposable email
	DisposableEmail bool `json:"disposable_email"`

	// EmotesOnly checks whether or not the message consists solely of emotes
	EmotesOnly bool `json:"emotes_only"`

	// Entropy checks whether the message text contains little informational context (i.e. is all punctuation, the same character, etc.)
	Entropy bool `json:"entropy"`

	// FollowersOnly checks whether followers_only mode has been enabled, and if so, whether the user can legally send a message
	FollowersOnly bool `json:"followers_only"`

	// SafeLinks checks whether any links include in the message text are unsafe for users/malicious
	SafeLinks bool `json:"safe_links"`

	// Spam checks whether the message text is highly likely to be spam
	Spam bool `json:"spam"`

	// SubscribersOnly checks whether subscribers_only mode is on, and if so, if the user is a subscriber to this channel (or a mod)
	SubscribersOnly bool `json:"subs_only"`

	// Suspended checks whether or not the sending user has a DMCA or TOS violation, or whether their account was deleted
	Suspended bool `json:"suspended"`

	// VerifiedOnly checks whether verified_only mode has been enabled, and if so, whether the user has a verified email address
	VerifiedOnly bool `json:"verified_only"`

	// Zalgo checks whether the message text is  "zalgo" or filled with diacritical marks that will overflow a text field
	Zalgo bool `json:"zalgo"`
}

// EnforcementConfiguration provides a series of knobs and bells that allow you to slightly tune the behavior
// of the enforcement engine
type EnforcementConfiguration struct {
	// DefaultAutoModLevel sets the automod level in the absence of a channel or other container
	DefaultAutoModLevel *int `json:"default_automod_level"`
}

// ConvertToRulesList converts an EnforcementRuleset into a list of strings
// the strings will correspond to each active rule
func (e EnforcementRuleset) ConvertToRulesList() []string {
	var rules []string
	if e.AutoMod {
		rules = append(rules, AutoModEnforcementName)
	}

	if e.Banned {
		rules = append(rules, BannedEnforcementName)
	}

	if e.Blocked {
		rules = append(rules, BlockedEnforcementName)
	}

	if e.DisposableEmail {
		rules = append(rules, DisposableEmailEnforcementName)
	}

	if e.EmotesOnly {
		rules = append(rules, EmoteOnlyEnforcementName)
	}

	if e.Entropy {
		rules = append(rules, EntropyEnforcementName)
	}

	if e.FollowersOnly {
		rules = append(rules, FollowersOnlyEnforcementName)
	}

	if e.SafeLinks {
		rules = append(rules, SafeLinksEnforcementName)
	}

	if e.Spam {
		rules = append(rules, SpamEnforcementName)
	}

	if e.SubscribersOnly {
		rules = append(rules, SubsOnlyEnforcementName)
	}

	if e.Suspended {
		rules = append(rules, SuspendedEnforcementName)
	}

	if e.VerifiedOnly {
		rules = append(rules, VerifiedOnlyEnforcementName)
	}

	if e.Zalgo {
		rules = append(rules, ZalgoEnforcementName)
	}

	return rules
}

// ExtractProperties contains all the information related to a user extraction
type ExtractProperties struct {
	Sender  MessageSender    `json:"sender"`
	Content MessageContentV2 `json:"content"`
}

// GenericEnforcementResponse contains the information about whether a message was accepted
type GenericEnforcementResponse struct {
	Passed bool `json:"passed"`
}

// AutoModResponse contains metadata when checking a message with AutoMod.
type AutoModResponse struct {
	GenericEnforcementResponse
	Reason              string `json:"reason"`
	IsClean             bool   `json:"is_clean"`
	ContainsBannedWords bool   `json:"contains_banned_words"`
}

// BannedResponse contains metadata about enforcing bans and timeouts.
type BannedResponse struct {
	GenericEnforcementResponse
	// EndTime indicates when a ban expires (i.e. a timeout). Nil if the ban is permanent.
	EndTime *time.Time `json:"end_time,omitempty"`
}

// FollowersOnlyResponse contains metadata about enforcing followers-only mode.
type FollowersOnlyResponse struct {
	GenericEnforcementResponse
	Exempt                bool           `json:"exempt"` // is this user exempt from FollowersOnly for some reason (sub, mod, etc.)
	FollowingDuration     time.Duration  `json:"following_duration"`
	RequiredFollowingTime *time.Duration `json:"minimum_following_duration"`
}

// SpamResponse contains metadata when checking a message with the spam classifier.
type SpamResponse struct {
	GenericEnforcementResponse
	FlagThreshold float64 `json:"flag_threshold"`
	DropThreshold float64 `json:"drop_threshold"`
	Score         float64 `json:"score"`
}

// EnforceProperties contains all the information related to enforcing rules on the message
type EnforceProperties struct {
	AllPassed       bool                        `json:"all_passed"`
	AutoMod         *AutoModResponse            `json:"automod,omitempty"`
	Banned          *BannedResponse             `json:"banned,omitempty"`
	Blocked         *GenericEnforcementResponse `json:"blocked,omitempty"`
	DisposableEmail *GenericEnforcementResponse `json:"disposable_email,omitempty"`
	EmoteOnly       *GenericEnforcementResponse `json:"emote_only,omitempty"`
	Entropy         *GenericEnforcementResponse `json:"entropy,omitempty"`
	FollowersOnly   *FollowersOnlyResponse      `json:"followers_only,omitempty"`
	SafeLinks       *GenericEnforcementResponse `json:"safe_links,omitempty"`
	Spam            *SpamResponse               `json:"spam,omitempty"`
	SubscribersOnly *GenericEnforcementResponse `json:"subscribers_only,omitempty"`
	Suspended       *GenericEnforcementResponse `json:"suspended,omitempty"`
	VerifiedOnly    *GenericEnforcementResponse `json:"verified_only,omitempty"`
	Zalgo           *GenericEnforcementResponse `json:"zalgo,omitempty"`
}
