package platform

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
)

var (
	errNotFound = fmt.Errorf("resource not found")
)

func ErrNotFound(err error) bool {
	return errors.Is(err, errNotFound)
}

type client struct {
	addr      string
	httClient *http.Client
}

func (c *client) GetCluster(ctx context.Context, project, cluster string) (*GetClusterResp, error) {
	url := c.url("/api/v1beta/projects/%s/clusters/%s", project, cluster)

	resp := &GetClusterResp{}
	if err := c.doRequest(ctx, http.MethodGet, url, nil, &resp); err != nil {
		return nil, err
	}
	return resp, nil
}

// doRequest send a http request and unmarshal the response to output.
func (c *client) doRequest(ctx context.Context, method, url string, payload []byte, output interface{}) error {
	req, err := http.NewRequestWithContext(ctx, method, url, bytes.NewBuffer(payload))
	if err != nil {
		return fmt.Errorf("create req failed: %s", err)
	}
	req.Header.Set("Content-Type", "application/json")

	httpResp, err := c.httClient.Do(req)
	if err != nil {
		return fmt.Errorf("send req failed: %s", err)
	}
	defer httpResp.Body.Close()

	respData, err := io.ReadAll(httpResp.Body)
	if err != nil {
		return fmt.Errorf("read resp body failed: %s", err)
	}

	if httpResp.StatusCode != http.StatusOK {
		if httpResp.StatusCode == http.StatusNotFound {
			return errNotFound
		}
		return fmt.Errorf("code:%s, msg:%s", httpResp.Status, string(respData))
	}

	if output != nil {
		return json.Unmarshal(respData, output)
	}
	return nil
}

func (c *client) url(format string, a ...any) string {
	return c.addr + fmt.Sprintf(format, a...)
}
