package clustermigratecli

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strconv"
	"time"
)

type Client struct {
	endpoint   string
	httpClient *http.Client
}

func NewClient(endpoint string) (*Client, error) {
	c := &Client{
		endpoint:   endpoint,
		httpClient: http.DefaultClient,
	}
	return c, nil
}

type MigrateClusterParam struct {
	Namespace    string
	Name         string
	TransferOnly bool
	DryRun       bool
	Clean        bool
}

func (c *Client) requestDoWithRetry(req *http.Request, retry int) ([]byte, error) {
	var lasterr error
	for i := retry; i >= 0; i-- {
		result, err := c.requestDo(req)
		if err == nil {
			return result, nil
		}
		if i > 0 {
			time.Sleep(500 * time.Millisecond)
		}
		lasterr = err
	}
	return nil, lasterr
}

func (c *Client) requestDo(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 {
		return nil, fmt.Errorf("statuscode:%d, resp body:%s", resp.StatusCode, string(data))
	}
	return data, nil
}

func (c *Client) MigrateCluster(ctx context.Context, param *MigrateClusterParam) error {
	query := make(url.Values)
	query.Add("namespace", param.Namespace)
	query.Add("cluster", param.Name)
	query.Add("transferOnly", strconv.FormatBool(param.TransferOnly))
	query.Add("dryRun", strconv.FormatBool(param.DryRun))
	query.Add("clean", strconv.FormatBool(param.Clean))
	req, err := http.NewRequestWithContext(ctx, http.MethodPost, fmt.Sprintf("%s?%s", c.endpoint, query.Encode()), nil)
	if err != nil {
		return err
	}
	if !param.TransferOnly {
		_, err = c.requestDoWithRetry(req, 2)
		return err
	} else {
		_, err = c.requestDo(req)
		return err
	}
}
