package o11ycli

import (
	"context"
	"fmt"
	"time"

	o11yapi "github.com/tidbcloud/devops/api/o11y"

	"github.com/go-resty/resty/v2"
)

type Client interface {
	GetCluster(ctx context.Context, cid string, req o11yapi.GetClusterRequest) (*o11yapi.GetClusterResponse, error)
	ListClusters(ctx context.Context, req o11yapi.ListClustersRequest) (*o11yapi.ListClustersResponse, error)
	CreateCluster(ctx context.Context, req o11yapi.CreateClusterRequest) (*o11yapi.CreateClusterResponse, error)
	DeleteCluster(ctx context.Context, cid string, req o11yapi.DeleteClusterRequest) (*o11yapi.DeleteClusterResponse, error)
}

type client struct {
	addr string
	raw  *resty.Client
}

func NewClient(addr string) (Client, error) {
	httpClient := resty.New().
		SetTimeout(10 * time.Second).
		SetScheme("https").
		SetBaseURL(addr).
		OnAfterResponse(func(c *resty.Client, r *resty.Response) error {
			if !r.IsSuccess() {
				return fmt.Errorf("rid: %s, status: %s, body: %s", r.Header().Get("x-request-id"), r.Status(), string(r.Body()))
			}
			return nil
		})

	c := &client{
		addr: addr,
		raw:  httpClient,
	}

	return c, nil
}

func (c *client) GetCluster(ctx context.Context, cid string, req o11yapi.GetClusterRequest) (*o11yapi.GetClusterResponse, error) {
	resp := &o11yapi.GetClusterResponse{}
	_, err := c.raw.R().
		SetContext(ctx).
		SetHeaders(c.praseBaseHeader(req.BaseRequest)).
		SetPathParam("cid", cid).
		SetResult(resp).
		Get("/api/v2/observability/clusters/{cid}/")
	return resp, err
}

func (c *client) ListClusters(ctx context.Context, req o11yapi.ListClustersRequest) (*o11yapi.ListClustersResponse, error) {
	params := map[string]string{}
	req.Inject(params)

	resp := &o11yapi.ListClustersResponse{}
	_, err := c.raw.R().
		SetContext(ctx).
		SetHeaders(c.praseBaseHeader(req.BaseRequest)).
		SetQueryParams(params).
		SetResult(resp).
		Get("/api/v2/observability/clusters")
	return resp, err
}

func (c *client) CreateCluster(ctx context.Context, req o11yapi.CreateClusterRequest) (*o11yapi.CreateClusterResponse, error) {
	resp := &o11yapi.CreateClusterResponse{}
	_, err := c.raw.R().
		SetContext(ctx).
		SetHeaders(c.praseBaseHeader(req.BaseRequest)).
		SetBody(req).
		SetResult(resp).
		Post("/api/v2/observability/clusters")
	return resp, err
}

func (c *client) DeleteCluster(ctx context.Context, cid string, req o11yapi.DeleteClusterRequest) (*o11yapi.DeleteClusterResponse, error) {
	resp := &o11yapi.DeleteClusterResponse{}
	_, err := c.raw.R().
		SetContext(ctx).
		SetHeaders(c.praseBaseHeader(req.BaseRequest)).
		SetPathParam("cid", cid).
		SetResult(resp).
		Delete("/api/v2/observability/clusters/{cid}")
	return resp, err
}

func (c *client) praseBaseHeader(req o11yapi.BaseRequest) map[string]string {
	m := map[string]string{}
	if req.Vendor != "" {
		m["x-vendor"] = req.Vendor
	}
	if req.Region != "" {
		m["x-region"] = req.Region
	}
	if req.OrgID != "" {
		m["x-org-id"] = req.OrgID
	}
	return m
}
