//go:generate ${GOBIN}/mockgen -destination client_mock.go -package=jumppodagentcli ${GO_MODULE}/pkg/infra/clients/jumppodagentcli Client
package jumppodagentcli

import (
	"context"
	"fmt"
	"net/url"

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

	"github.com/tidbcloud/devops/api"
	jmpapi "github.com/tidbcloud/devops/api/jump"
	"github.com/tidbcloud/devops/pkg/infra/consts"
)

type Client interface {
	TailscaleUp(ctx context.Context, req jmpapi.TailscaleUpRequest) error
	TailscaleDown(ctx context.Context) error
	TailscaleStatus(ctx context.Context) (*jmpapi.TailscaleStatus, error)
	GetKubernetesCredential(ctx context.Context, req jmpapi.GetKubernetesCredentialRequest) ([]byte, error)
}

type client struct {
	raw *resty.Client
}

func NewClient(podNamespace, podName string) Client {
	podAddr := fmt.Sprintf("%s.%s.%s", podName, "jump-pod-peer", podNamespace)
	baseURL := fmt.Sprintf("http://%s:%d", podAddr, consts.JumpPodAgentPort)

	return &client{
		raw: resty.New().SetBaseURL(baseURL),
	}
}

func (c *client) TailscaleUp(ctx context.Context, req jmpapi.TailscaleUpRequest) error {
	resp, err := c.raw.R().
		SetContext(ctx).
		SetBody(req).
		Post("/tailscale/up")
	if err != nil {
		return fmt.Errorf("request failed: %w", err)
	}
	if !resp.IsSuccess() {
		return fmt.Errorf("code: %d, body: %s", resp.StatusCode(), string(resp.Body()))
	}

	return nil
}

func (c *client) TailscaleDown(ctx context.Context) error {
	resp, err := c.raw.R().
		SetContext(ctx).
		Post("/tailscale/down")
	if err != nil {
		return fmt.Errorf("request failed: %w", err)
	}
	if !resp.IsSuccess() {
		return fmt.Errorf("code: %d, body: %s", resp.StatusCode(), string(resp.Body()))
	}

	return nil
}

func (c *client) TailscaleStatus(ctx context.Context) (*jmpapi.TailscaleStatus, error) {
	result := &jmpapi.TailscaleStatusResponse{}
	resp, err := c.raw.R().
		SetContext(ctx).
		SetResult(result).
		Get("/tailscale/status")
	if err != nil {
		return nil, fmt.Errorf("request failed: %w", err)
	}
	if !resp.IsSuccess() {
		return nil, fmt.Errorf("code: %d, body: %s", resp.StatusCode(), string(resp.Body()))
	}

	return result.Status, nil
}

func (c *client) GetKubernetesCredential(ctx context.Context, req jmpapi.GetKubernetesCredentialRequest) ([]byte, error) {
	query := url.Values{}
	for _, credID := range req.CredIDs {
		query.Add("cred_id", string(credID))
	}

	result := &jmpapi.GetKubernetesCredentialResponse{}
	resp, err := c.raw.R().
		SetContext(ctx).
		SetQueryParamsFromValues(query).
		SetResult(result).
		Get("/kubernetes/credential")
	if err != nil {
		return nil, fmt.Errorf("request failed: %w", err)
	}
	if !resp.IsSuccess() {
		return nil, fmt.Errorf("code: %d, body: %s", resp.StatusCode(), string(resp.Body()))
	}
	if result.ErrCode != api.ErrCodeOK {
		return nil, fmt.Errorf("err_code: %s, err_message: %s", result.ErrCode, result.ErrMessage)
	}

	return result.Kubeconfig, nil
}
