package ops

import (
	"encoding/json"
	"fmt"
	"strconv"

	"github.com/gavv/httpexpect/v2"
	"github.com/tidbcloud/qa-PlatformAPIAuto/common"
	opsmod "github.com/tidbcloud/qa-PlatformAPIAuto/models/ops"
	"github.com/tidbcloud/qa-gourd/ProductService"
	"github.com/tidbcloud/qa-gourd/handler"
)

type client struct {
	w    *ProductService.WebRequestInfo
	urls map[string]ProductService.UrlInfo
}

func (c *client) GetClusterConfiguration(clusterId string) (*opsmod.CloudconfigGetConfigurationResp, error) {
	queryParam := map[string]string{
		"cluster_type": string(opsmod.CloudconfigClusterTypeDEDICATEDTIDB),
		"cluster_id":   clusterId,
	}
	resp := c.w.DoWebAPIRequestByUrlInfo(c.urls["opsGetClusterConfiguration"], nil, nil, queryParam)

	obj := &opsmod.CloudconfigGetConfigurationResp{}
	err := c.handleResp(resp, obj)
	if err != nil {
		return nil, err
	}
	err = c.handleBaseResp(obj.Errcode, obj.Errmsg)
	if err != nil {
		return nil, err
	}

	return obj, nil
}

func (c *client) GetTenantInitConfiguration(tenantID string) (*opsmod.CloudconfigGetConfigurationResp, error) {
	queryParam := map[string]string{
		"cluster_type": string(opsmod.CloudconfigClusterTypeDEDICATEDTIDB),
		"tenant_id":    tenantID,
	}
	resp := c.w.DoWebAPIRequestByUrlInfo(c.urls["opsGetTenantInitConfiguration"], nil, nil, queryParam)

	obj := &opsmod.CloudconfigGetConfigurationResp{}
	err := c.handleResp(resp, obj)
	if err != nil {
		return nil, err
	}
	err = c.handleBaseResp(obj.Errcode, obj.Errmsg)
	if err != nil {
		return nil, err
	}

	return obj, nil
}

func (c *client) PreviewClusterConfiguration(req *opsmod.CloudconfigPreviewClusterConfigurationChangeReq) (*opsmod.CloudconfigPreviewConfigurationChangeResp, error) {
	resp := c.w.DoWebAPIRequestByUrlInfo(c.urls["opsPreviewConfigurationChange"], req, nil, nil)

	obj := &opsmod.CloudconfigPreviewConfigurationChangeResp{}
	err := c.handleResp(resp, obj)
	if err != nil {
		return nil, err
	}
	err = c.handleBaseResp(obj.Errcode, obj.Errmsg)
	if err != nil {
		return nil, err
	}

	return obj, nil
}

func (c *client) PreviewTenantInitConfiguration(req *opsmod.CloudconfigPreviewTenantInitConfigurationChangeReq) (*opsmod.CloudconfigPreviewConfigurationChangeResp, error) {
	resp := c.w.DoWebAPIRequestByUrlInfo(c.urls["opsPreviewTenantInitConfiguration"], req, nil, nil)

	obj := &opsmod.CloudconfigPreviewConfigurationChangeResp{}
	err := c.handleResp(resp, obj)
	if err != nil {
		return nil, err
	}
	err = c.handleBaseResp(obj.Errcode, obj.Errmsg)
	if err != nil {
		return nil, err
	}

	return obj, nil
}

func (c *client) CreateClusterConfigChange(req *opsmod.CloudconfigCreateClusterConfigurationChangeReq) (*opsmod.CloudconfigCreateConfigurationChangeResp, error) {
	resp := c.w.DoWebAPIRequestByUrlInfo(c.urls["opsCreateClusterConfigChange"], req, nil, nil)

	obj := &opsmod.CloudconfigCreateConfigurationChangeResp{}
	err := c.handleResp(resp, obj)
	if err != nil {
		return nil, err
	}
	err = c.handleBaseResp(obj.Errcode, obj.Errmsg)
	if err != nil {
		return nil, err
	}

	return obj, nil
}

func (c *client) GetConfigChange(id int64) (*opsmod.GithubComTidbcloudDevopsEntityCloudconfigConfigurationChange, error) {
	c.w.SetToken(c.w.GetToken(handler.OtherUserInfo.OpsAdminEmail))
	pathParam := map[string]string{
		"change_id": strconv.FormatInt(id, 10),
	}
	resp := c.w.DoWebAPIRequestByUrlInfo(c.urls["opsGetConfigChange"], nil, pathParam, nil)

	obj := &opsmod.CloudconfigGetConfigurationChangeResp{}
	err := c.handleResp(resp, obj)
	if err != nil {
		return nil, err
	}
	err = c.handleBaseResp(obj.Errcode, obj.Errmsg)
	if err != nil {
		return nil, err
	}

	return obj.Change, nil
}

func (c *client) ApplyConfigChange(id int64) error {
	pathParam := map[string]string{
		"change_id": strconv.FormatInt(id, 10),
	}
	body := &opsmod.CloudconfigApplyConfigurationChangeReq{}
	resp := c.w.DoWebAPIRequestByUrlInfo(c.urls["opsApplyConfigChange"], body, pathParam, nil)

	obj := &opsmod.APIBaseResp{}
	err := c.handleResp(resp, obj)
	if err != nil {
		return err
	}
	err = c.handleBaseResp(obj.Errcode, obj.Errmsg)
	if err != nil {
		return err
	}

	return nil
}

func (t *client) handleResp(resp *httpexpect.Response, obj interface{}) error {
	httpInfo := common.ParseHttpInfo(resp)
	if httpInfo.RespStatusCode != common.StatusOK {
		return fmt.Errorf("api failed with code:%d msg:%s", httpInfo.RespStatusCode, httpInfo.RespBody)
	}

	err := json.Unmarshal([]byte(httpInfo.RespBody), obj)
	if err != nil {
		return fmt.Errorf("unmarshal failed :%v", err)
	}

	return nil
}

func (t *client) handleBaseResp(code opsmod.APIErrCode, msg string) error {
	if code != opsmod.APIErrCodeOK {
		return fmt.Errorf("errcode:%s errmsg:%s", code, msg)
	}

	return nil
}
