package alarmrule

import (
	"log"

	"github.com/chnsz/golangsdk"
)

type CreateOptsBuilder interface {
	ToAlarmRuleCreateMap() (map[string]interface{}, error)
}

type DimensionOpts struct {
	Name  string `json:"name" required:"true"`
	Value string `json:"value" required:"true"`
}

type MetricOpts struct {
	Namespace  string          `json:"namespace" required:"true"`
	MetricName string          `json:"metric_name" required:"true"`
	Dimensions []DimensionOpts `json:"dimensions,omitempty"`
}

type ConditionOpts struct {
	// The value can be 0
	Period             int    `json:"period"`
	Filter             string `json:"filter" required:"true"`
	ComparisonOperator string `json:"comparison_operator" required:"true"`
	// The Value ranges from 0 to MAX_VALUE
	Value int    `json:"value"`
	Unit  string `json:"unit,omitempty"`
	Count int    `json:"count" required:"true"`
	// The value can be 0
	SuppressDuration int `json:"suppress_duration"`
}

type ActionOpts struct {
	Type             string   `json:"type" required:"true"`
	NotificationList []string `json:"notificationList" required:"true"`
}

type CreateOpts struct {
	AlarmName               string        `json:"alarm_name" required:"true"`
	AlarmDescription        string        `json:"alarm_description,omitempty"`
	AlarmType               string        `json:"alarm_type,omitempty"`
	AlarmLevel              int           `json:"alarm_level,omitempty"`
	Metric                  MetricOpts    `json:"metric" required:"true"`
	Condition               ConditionOpts `json:"condition" required:"true"`
	AlarmActions            []ActionOpts  `json:"alarm_actions,omitempty"`
	InsufficientdataActions []ActionOpts  `json:"insufficientdata_actions,omitempty"`
	OkActions               []ActionOpts  `json:"ok_actions,omitempty"`
	AlarmEnabled            bool          `json:"alarm_enabled"`
	AlarmActionEnabled      bool          `json:"alarm_action_enabled"`
	EnterpriseProjectID     string        `json:"enterprise_project_id,omitempty"`
}

func (opts CreateOpts) ToAlarmRuleCreateMap() (map[string]interface{}, error) {
	return golangsdk.BuildRequestBody(opts, "")
}

func Create(c *golangsdk.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
	b, err := opts.ToAlarmRuleCreateMap()
	if err != nil {
		r.Err = err
		return
	}
	log.Printf("[DEBUG] create AlarmRule url:%q, body=%#v, opt=%#v", rootURL(c), b, opts)
	reqOpt := &golangsdk.RequestOpts{OkCodes: []int{201}}
	_, r.Err = c.Post(rootURL(c), b, &r.Body, reqOpt)
	return
}

func Get(c *golangsdk.ServiceClient, id string) (r GetResult) {
	_, r.Err = c.Get(resourceURL(c, id), &r.Body, nil)
	return
}

type UpdateOptsBuilder interface {
	ToAlarmRuleUpdateMap() (map[string]interface{}, error)
}

type UpdateOpts struct {
	Name          string         `json:"alarm_name,omitempty"`
	AlarmType     string         `json:"alarm_type,omitempty"`
	AlarmLevel    int            `json:"alarm_level,omitempty"`
	Description   *string        `json:"alarm_description,omitempty"`
	ActionEnabled *bool          `json:"alarm_action_enabled,omitempty"`
	Condition     *ConditionOpts `json:"condition,omitempty"`
	// in actual, alarm_actions and ok_actions don't support to update
	AlarmActions []ActionOpts `json:"alarm_actions,omitempty"`
	OkActions    []ActionOpts `json:"ok_actions,omitempty"`
}

func (opts UpdateOpts) ToAlarmRuleUpdateMap() (map[string]interface{}, error) {
	return golangsdk.BuildRequestBody(opts, "")
}

func Update(c *golangsdk.ServiceClient, id string, opts UpdateOpts) (r UpdateResult) {
	b, err := opts.ToAlarmRuleUpdateMap()
	if err != nil {
		r.Err = err
		return
	}
	_, r.Err = c.Put(resourceURL(c, id), b, nil, &golangsdk.RequestOpts{
		OkCodes: []int{204},
	})
	return
}

type EnableOptsBuilder interface {
	ToAlarmRuleEnableMap() (map[string]interface{}, error)
}

type EnableOpts struct {
	AlarmEnabled bool `json:"alarm_enabled"`
}

func (opts EnableOpts) ToAlarmRuleEnableMap() (map[string]interface{}, error) {
	return golangsdk.BuildRequestBody(opts, "")
}

func Enable(c *golangsdk.ServiceClient, id string, opts EnableOpts) (r EnableResult) {
	b, err := opts.ToAlarmRuleEnableMap()
	if err != nil {
		r.Err = err
		return
	}
	_, r.Err = c.Put(actionURL(c, id), b, nil, &golangsdk.RequestOpts{
		OkCodes: []int{204},
	})
	return
}

func Delete(c *golangsdk.ServiceClient, id string) (r DeleteResult) {
	reqOpt := &golangsdk.RequestOpts{OkCodes: []int{204}}
	_, r.Err = c.Delete(resourceURL(c, id), reqOpt)
	return
}
