package cluster

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"time"

	clusterctlpb "github.com/tidbcloud/infra-provider/api/tidbcloud/cluster-server/v1"
	spb "google.golang.org/genproto/googleapis/rpc/status"
	grpcstatus "google.golang.org/grpc/status"
	"google.golang.org/protobuf/encoding/protojson"
)

type ClusterCli struct {
	endpoint     string
	httpClient   *http.Client
	marshalOpt   protojson.MarshalOptions
	unmarshalOpt protojson.UnmarshalOptions
}

func NewClusterCli(endpoint string) *ClusterCli {
	return &ClusterCli{
		endpoint: endpoint,
		httpClient: &http.Client{
			Timeout: 10 * time.Second,
		},
		marshalOpt: protojson.MarshalOptions{
			UseProtoNames:   false,
			EmitUnpopulated: true,
		},
		unmarshalOpt: protojson.UnmarshalOptions{
			DiscardUnknown: true,
		},
	}
}

func (c *ClusterCli) GetCluster(ctx context.Context, in *clusterctlpb.GetClusterRequest) (*clusterctlpb.Cluster, error) {
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s/api/v1/clusters/%v", c.endpoint, in.GetClusterId()), nil)
	if err != nil {
		return nil, err
	}
	data, err := requestDo(c, req)
	if err != nil {
		return nil, err
	}
	out := new(clusterctlpb.Cluster)
	if err := c.unmarshalOpt.Unmarshal(data, out); err != nil {
		return nil, err
	}
	return out, nil
}

func requestDo(c *ClusterCli, req *http.Request) ([]byte, error) {
	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	data, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode > 300 {
		status := new(spb.Status)
		if err := c.unmarshalOpt.Unmarshal(data, status); err != nil {
			return nil, err
		}
		return nil, grpcstatus.ErrorProto(status)
	}
	return data, nil
}
