package dispatch

import "time"

type (
	PolicyStatus       string
	ConditionOperator  string
	Weekday            string
	ReceiverType       string
	AssignmentStrategy string
	ActionType         string
	NoopResult         string
	EscalateTo         string
	TransitionType     string
	WebRequestMethod   string
)

const (
	PolicyStatusDraft   PolicyStatus = "draft"
	PolicyStatusActive  PolicyStatus = "active"
	PolicyStatusRetired PolicyStatus = "retired"

	ConditionOperatorEqual                    ConditionOperator = "eq"
	ConditionOperatorNotEqual                 ConditionOperator = "ne"
	ConditionOperatorIn                       ConditionOperator = "in"
	ConditionOperatorNotIn                    ConditionOperator = "not_in"
	ConditionOperatorRegex                    ConditionOperator = "regex"
	ConditionOperatorContains                 ConditionOperator = "contains"
	ConditionOperatorExists                   ConditionOperator = "exists"
	ConditionOperatorNotExists                ConditionOperator = "not_exists"
	ConditionOperatorWithinWeeklyTimeWindow   ConditionOperator = "within_weekly_time_window"
	ConditionOperatorOverlapsWeeklyTimeWindow ConditionOperator = "overlaps_weekly_time_window"
	ConditionOperatorWithinCalendarEvent      ConditionOperator = "within_calendar_event"

	WeekdayMonday    Weekday = "MON"
	WeekdayTuesday   Weekday = "TUE"
	WeekdayWednesday Weekday = "WED"
	WeekdayThursday  Weekday = "THU"
	WeekdayFriday    Weekday = "FRI"
	WeekdaySaturday  Weekday = "SAT"
	WeekdaySunday    Weekday = "SUN"

	ReceiverTypeUser       ReceiverType = "user"
	ReceiverTypeUsers      ReceiverType = "users"
	ReceiverTypeBot        ReceiverType = "bot"
	ReceiverTypeGroup      ReceiverType = "group"
	ReceiverTypeOncallTeam ReceiverType = "oncall_team"

	AssignmentStrategyFirst      AssignmentStrategy = "first"
	AssignmentStrategyRoundRobin AssignmentStrategy = "round_robin"

	ActionTypeAssign                      ActionType = "assign"
	ActionTypeAssignL2                    ActionType = "assign_l2"
	ActionTypeEscalate                    ActionType = "escalate"
	ActionTypeRetrigger                   ActionType = "retrigger"
	ActionTypeNoop                        ActionType = "noop"
	ActionTypeTriage                      ActionType = "triage"
	ActionTypeTransitionIssue             ActionType = "transition_issue"
	ActionTypeSendWebRequest              ActionType = "send_web_request"
	ActionTypeSendAssignmentNotification  ActionType = "send_assignment_notification"
	ActionTypeMarkAssignmentMessageUrgent ActionType = "mark_assignment_message_urgent"
	ActionTypePageAssignment              ActionType = "page_assignment"
	ActionTypeEscalateAssignmentToLeader  ActionType = "escalate_assignment_to_leader"

	NoopResultSuccess NoopResult = "success"
	NoopResultFailure NoopResult = "failure"

	EscalateToL3 EscalateTo = "L3"

	TransitionTypeContinue  TransitionType = "continue"
	TransitionTypeTerminate TransitionType = "terminate"

	WebRequestMethodGet    WebRequestMethod = "GET"
	WebRequestMethodPost   WebRequestMethod = "POST"
	WebRequestMethodPut    WebRequestMethod = "PUT"
	WebRequestMethodPatch  WebRequestMethod = "PATCH"
	WebRequestMethodDelete WebRequestMethod = "DELETE"
)

type WeeklyTimeWindow struct {
	Timezone string    `json:"timezone"`
	Weekdays []Weekday `json:"weekdays"`
	Start    string    `json:"start"`
	End      string    `json:"end"`
}

type ConditionExpr struct {
	All []ConditionExpr `json:"all,omitempty"`
	Any []ConditionExpr `json:"any,omitempty"`
	Not *ConditionExpr  `json:"not,omitempty"`

	Always bool `json:"always,omitempty"`

	Field            *string            `json:"field,omitempty"`
	Operator         *ConditionOperator `json:"operator,omitempty"`
	Value            *string            `json:"value,omitempty"`
	Values           []string           `json:"values,omitempty"`
	WeeklyTimeWindow *WeeklyTimeWindow  `json:"weekly_time_window,omitempty"`
	CalendarName     *string            `json:"calendar_name,omitempty"`
}

type ReceiverMapping struct {
	Field        string              `json:"field" binding:"required"`
	NameToValues map[string][]string `json:"name_to_values" binding:"required"`
	Default      string              `json:"default" binding:"required"`
}

type Receiver struct {
	Type    ReceiverType     `json:"type"`
	Name    string           `json:"name,omitempty"`
	User    *string          `json:"user,omitempty"`
	Users   []string         `json:"users,omitempty"`
	Bot     *string          `json:"bot,omitempty"`
	Mapping *ReceiverMapping `json:"mapping,omitempty"`
}

type OncallLookup struct {
	Range string `json:"range" binding:"required"`
	Step  string `json:"step" binding:"required"`
}

type AssignAction struct {
	Receiver     *Receiver           `json:"receiver,omitempty"`
	Strategy     *AssignmentStrategy `json:"strategy,omitempty"`
	OncallLookup *OncallLookup       `json:"oncall_lookup,omitempty"`
}

type RetriggerAction struct {
	Delay string `json:"delay"`
}

type NoopAction struct {
	Result NoopResult `json:"result" binding:"required"`
}

type EscalateAction struct {
	EscalateTo EscalateTo `json:"escalate_to" binding:"required"`
}

type TransitionIssueAction struct {
	TargetStatus string `json:"target_status" binding:"required"`
}

type SendWebRequestAction struct {
	URL     string            `json:"url" binding:"required"`
	Method  WebRequestMethod  `json:"method" binding:"required"`
	Body    string            `json:"body,omitempty"`
	Headers map[string]string `json:"headers,omitempty"`
}

type AssignmentRole string

const (
	AssignmentRoleAssignee   AssignmentRole = "assignee"
	AssignmentRoleL2Assignee AssignmentRole = "l2_assignee"
)

type SendAssignmentNotificationAction struct {
	Role  AssignmentRole `json:"role"`
	Label string         `json:"label"`
}

type PageAssignmentAction struct {
	Attempt            int      `json:"attempt"`
	AckPendingStatuses []string `json:"ack_pending_statuses"`
	AckTimeout         string   `json:"ack_timeout"`
	PollInterval       string   `json:"poll_interval"`
}

type Action struct {
	Type                       ActionType                        `json:"type"`
	Assign                     *AssignAction                     `json:"assign,omitempty"`
	AssignL2                   *AssignAction                     `json:"assign_l2,omitempty"`
	Escalate                   *EscalateAction                   `json:"escalate,omitempty"`
	Retrigger                  *RetriggerAction                  `json:"retrigger,omitempty"`
	Noop                       *NoopAction                       `json:"noop,omitempty"`
	TransitionIssue            *TransitionIssueAction            `json:"transition_issue,omitempty"`
	SendWebRequest             *SendWebRequestAction             `json:"send_web_request,omitempty"`
	SendAssignmentNotification *SendAssignmentNotificationAction `json:"send_assignment_notification,omitempty"`
	PageAssignment             *PageAssignmentAction             `json:"page_assignment,omitempty"`
}

type Transition struct {
	OnSuccess TransitionType `json:"on_success"`
}

type Rule struct {
	ID         uint64        `json:"id"`
	Name       string        `json:"name"`
	Priority   int           `json:"priority"`
	When       ConditionExpr `json:"when"`
	Then       []Action      `json:"then"`
	Transition Transition    `json:"transition"`
}

type PolicyTrigger struct {
	PolicyID      uint64   `json:"policy_id"`
	Enable        bool     `json:"enable"`
	SourceIn      []string `json:"source_in,omitempty"`
	IssueLabelAll []string `json:"issue_label_all,omitempty"`
	IssueStatusIn []string `json:"issue_status_in,omitempty"`
	ProjectKeyIn  []string `json:"project_key_in,omitempty"`
}

type Policy struct {
	ID               uint64        `json:"id"`
	FamilyID         string        `json:"family_id"`
	Name             string        `json:"name"`
	Version          *int          `json:"version"`
	Status           PolicyStatus  `json:"status"`
	Rules            []Rule        `json:"rules"`
	ReplacesPolicyID *uint64       `json:"replaces_policy_id,omitempty"`
	Trigger          PolicyTrigger `json:"trigger"`

	CreatedBy   string     `json:"created_by"`
	PublishedBy string     `json:"published_by,omitempty"`
	PublishedAt *time.Time `json:"published_at,omitempty"`
	CreatedAt   time.Time  `json:"created_at"`
	UpdatedAt   *time.Time `json:"updated_at,omitempty"`
}
