package sdk

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"github.com/tidbcloud/config-service/sdk/api"
)

type Client struct {
	BaseURL string
	Client  *http.Client

	path string
	body interface{}
}

func New(baseURL string) *Client {
	cli := &http.Client{
		Timeout: time.Second * 10,
	}
	return &Client{
		BaseURL: baseURL,
		Client:  cli,
	}
}

func (c *Client) setPath(path string) *Client {
	c.path = path
	return c
}

func (c *Client) setBody(body interface{}) *Client {
	c.body = body
	return c
}

func (c *Client) do(v interface{}) error {
	payloadBuf := new(bytes.Buffer)
	err := json.NewEncoder(payloadBuf).Encode(&c.body)
	if err != nil {
		return err
	}

	req, err := http.NewRequest(http.MethodPost, strings.TrimRight(c.BaseURL, "/")+c.path, payloadBuf)
	if err != nil {
		return err
	}
	res, err := c.Client.Do(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if res.StatusCode == 200 {
		err = json.NewDecoder(res.Body).Decode(&v)
		if err != nil {
			return err
		}
		return nil
	} else {
		body, err := ioutil.ReadAll(res.Body)
		if err != nil {
			return err
		}
		return fmt.Errorf(string(body))
	}
}

func (c *Client) DescribeClusterConfiguration(input *api.DescribeClusterConfigInput) (*api.DescribeClusterConfigOutput, error) {
	var output api.DescribeClusterConfigOutput
	err := c.setPath("/api/v1/cluster/configuration").setBody(&input).do(&output)
	return &output, err
}

func (c *Client) DescribeBackupConfiguration(input *api.DescribeBRConfigInput) (*api.DescribeBRConfigOutput, error) {
	var output api.DescribeBRConfigOutput
	err := c.setPath("/api/v1/backup/configuration").setBody(&input).do(&output)
	return &output, err
}

func (c *Client) DescribeRestoreConfiguration(input *api.DescribeBRConfigInput) (*api.DescribeBRConfigOutput, error) {
	var output api.DescribeBRConfigOutput
	err := c.setPath("/api/v1/restore/configuration").setBody(&input).do(&output)
	return &output, err
}
