package vultr

import (
	"encoding/json"
	"fmt"
	"net/url"

	"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
)

// ListInstanceResponse is the response structure of Vultr ListInstance API.
type ListInstanceResponse struct {
	Instances []Instance `json:"instances"`
	Meta      *Meta      `json:"Meta"`
}

// Instance represents Vultr Instance (VPS).
// See: https://github.com/vultr/govultr/blob/5125e02e715ae6eb3ce854f0e7116c7ce545a710/instance.go#L81
type Instance struct {
	ID               string   `json:"id"`
	Os               string   `json:"os"`
	RAM              int      `json:"ram"`
	Disk             int      `json:"disk"`
	MainIP           string   `json:"main_ip"`
	VCPUCount        int      `json:"vcpu_count"`
	Region           string   `json:"region"`
	ServerStatus     string   `json:"server_status"`
	AllowedBandwidth int      `json:"allowed_bandwidth"`
	V6MainIP         string   `json:"v6_main_ip"`
	Hostname         string   `json:"hostname"`
	Label            string   `json:"label"`
	InternalIP       string   `json:"internal_ip"`
	OsID             int      `json:"os_id"`
	Features         []string `json:"features"`
	Plan             string   `json:"plan"`
	Tags             []string `json:"tags"`

	// The following fields are defined in the response but are not used during service discovery.
	//DefaultPassword string `json:"default_password,omitempty"`
	//DateCreated     string `json:"date_created"`
	//Status          string `json:"status"`
	//PowerStatus     string `json:"power_status"`
	//NetmaskV4       string `json:"netmask_v4"`
	//GatewayV4       string `json:"gateway_v4"`
	//V6Network       string `json:"v6_network"`
	//V6NetworkSize   int    `json:"v6_network_size"`
	//// Deprecated: Tag should no longer be used. Instead, use Tags.
	//Tag             string `json:"tag"`
	//KVM             string `json:"kvm"`
	//AppID           int    `json:"app_id"`
	//ImageID         string `json:"image_id"`
	//FirewallGroupID string `json:"firewall_group_id"`
	//UserScheme      string `json:"user_scheme"`
}

// Meta represents the available pagination information
type Meta struct {
	Total int `json:"total"`
	Links *Links
}

// Links represent the next/previous cursor in your pagination calls
type Links struct {
	Next string `json:"next"`
	Prev string `json:"prev"`
}

// getInstances retrieve instance from Vultr HTTP API.
func getInstances(cfg *apiConfig) ([]Instance, error) {
	var instances []Instance

	// prepare GET params
	params := url.Values{}
	params.Set("per_page", "100")
	params.Set("label", cfg.label)
	params.Set("main_ip", cfg.mainIP)
	params.Set("region", cfg.region)
	params.Set("firewall_group_id", cfg.firewallGroupID)
	params.Set("hostname", cfg.hostname)

	// send request to vultr API
	for {
		// See: https://www.vultr.com/api/#tag/instances/operation/list-instances
		path := fmt.Sprintf("/v2/instances?%s", params.Encode())
		resp, err := cfg.c.GetAPIResponse(path)
		if err != nil {
			logger.Errorf("get response from vultr failed, path:%s, err: %v", path, err)
			return nil, err
		}

		var listInstanceResp ListInstanceResponse
		if err = json.Unmarshal(resp, &listInstanceResp); err != nil {
			logger.Errorf("unmarshal response from vultr failed, err: %v", err)
			return nil, err
		}

		instances = append(instances, listInstanceResp.Instances...)

		if listInstanceResp.Meta != nil && listInstanceResp.Meta.Links != nil && listInstanceResp.Meta.Links.Next != "" {
			// if `next page` is available, set the cursor param and request again.
			params.Set("cursor", listInstanceResp.Meta.Links.Next)
		} else {
			// otherwise exit the loop
			break
		}
	}

	return instances, nil
}