package curl

import (
	"bytes"
	"context"
	"fmt"
	"time"

	"github.com/go-resty/resty/v2"
	"github.com/zeromicro/go-zero/core/logc"
	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/core/trace"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/propagation"
	oteltrace "go.opentelemetry.io/otel/trace"
)

func NewClient(ctx context.Context, c *Config) Client {
	// 创建一个restry客户端
	client := resty.New().SetBaseURL(c.BaseUrl)

	// 设置超时时间为 5 分钟
	if c.RequireTimeout == 0 {
		client.SetTimeout(5 * time.Minute)
	}
	/* 传输链路 */
	tracer := otel.GetTracerProvider().Tracer(trace.TraceName)
	spanCtx, span := tracer.Start(
		ctx,
		"client_resty_send",
		oteltrace.WithSpanKind(oteltrace.SpanKindClient),
	)
	carrier := &propagation.HeaderCarrier{}
	otel.GetTextMapPropagator().Inject(spanCtx, carrier)
	for _, cacarrierKey := range carrier.Keys() {
		client.SetHeader(cacarrierKey, carrier.Get(cacarrierKey))
	}
	defer span.End()
	/* 传输链路 */

	if c.HeaderData != nil {
		for k, v := range c.HeaderData {
			client = client.SetHeader(k, v)
		}
	}

	if c.RetryCount > 0 {
		client = client.SetRetryCount(int(c.RetryCount))
	}

	if c.RetryWaitTime > 0 {
		client = client.SetRetryWaitTime(time.Duration(c.RetryWaitTime) * time.Second)
	}

	return &defaultClient{
		client: client,
		c:      c,
		ctx:    ctx,
	}
}

type (
	Config struct {
		BaseUrl        string            `json:"base_url"`
		Url            string            `json:"url"`
		HeaderData     map[string]string `json:"header_data"`
		RetryCount     int64             `json:"retry_count"`
		RetryWaitTime  int64             `json:"retry_wait_time"`
		RequireTimeout time.Duration     `json:"require_timeout"`
	}
	defaultClient struct {
		c      *Config
		client *resty.Client
		ctx    context.Context
	}

	Client = interface {
		// PostJson请求
		PostJson(jsonData interface{}, res interface{}) error
		// PostForm请求
		PostForm(formData map[string]string, res interface{}) (interface{}, error)
		// 上传文件
		PostFile(fileParam string, fileName string, res interface{}, profileBytes []byte, formData map[string]string) (interface{}, error)
	}
)

// PostJson请求
func (c *defaultClient) PostJson(jsonData interface{}, res interface{}) error {
	//logc.Infof(c.ctx, "客户端名称 Client PostJson jsonData:%+v", jsonData)

	logc.Infof(c.ctx, "客户端名称 请求开始时间:%+v", time.Now().UTC())
	resp, err := c.client.
		SetHeader("Accept", "application/json").
		SetHeader("Content-Type", "application/json").
		R().
		SetContext(c.ctx).
		SetResult(res).
		SetBody(jsonData).
		Post(c.c.Url)

	if err != nil {
		logc.Errorf(c.ctx, "客户端 请求失败 Client PostForm error:%+v", err)
		return err
	}
	logc.Infof(c.ctx, "客户端名称 请求结束时间:%+v", time.Now().UTC())

	logc.Infof(c.ctx, "客户端 请求返回结果 Client PostForm RawResponse result:%+v,%+V", resp.RawResponse.Status, resp.RawResponse.StatusCode)

	//logc.Infof(c.ctx, "客户端 请求返回结果 Client PostForm res result:%+v", res)
	if resp.StatusCode() != 200 {
		err = fmt.Errorf("服务端失败,返回结果:%+v", resp.RawResponse.Status)
		logx.Errorf("客户端 请求失败 Client PostForm Server error:%+v", err)
	}
	return err
}

// PostForm请求
func (c *defaultClient) PostForm(formData map[string]string, res interface{}) (interface{}, error) {
	resp, err := c.client.
		SetHeader("Accept", "application/json").
		SetHeader("Content-Type", "multipart/form-data").
		R().
		SetContext(c.ctx).
		SetResult(res).
		SetFormData(formData).
		Post(c.c.Url)

	if err != nil {
		logc.Errorf(c.ctx, "客户端 请求失败 Client PostForm error:%+v", err)
		return res, err
	}
	logc.Infof(c.ctx, "客户端 请求返回结果 Client PostForm RawResponse result:%+v,%+V", resp.RawResponse.Status, resp.RawResponse.StatusCode)
	logc.Infof(c.ctx, "客户端 请求返回结果 Client PostForm res result:%+v", res)
	if resp.StatusCode() != 200 {
		err = fmt.Errorf("服务端失败,返回结果:%+v", resp.RawResponse.Status)
		logx.Errorf("客户端 请求失败 Client PostForm Server error:%+v", err)
	}
	return res, err
}

// 上传文件
func (c *defaultClient) PostFile(fileParam string, fileName string, res interface{}, profileBytes []byte, formData map[string]string) (interface{}, error) {

	resp, err := c.client.
		SetHeader("Accept", "application/json").
		SetHeader("Content-Type", "multipart/form-data").
		R().
		SetContext(c.ctx).
		SetResult(res).
		SetFileReader(fileParam, fileName, bytes.NewReader(profileBytes)).
		SetFormData(formData).
		Post(c.c.Url)

	if err != nil {
		logc.Errorf(c.ctx, "客户端 请求失败 Client PostFile error:%+v", err)
		return res, err
	}
	logc.Infof(c.ctx, "客户端 请求返回结果 Client PostFile RawResponse result:%+v,%+V", resp.RawResponse.Status, resp.RawResponse.StatusCode)
	logc.Infof(c.ctx, "客户端 请求返回结果 Client PostFile res result:%+v", res)
	if resp.StatusCode() != 200 {
		err = fmt.Errorf("服务端失败,返回结果:%+v", resp.RawResponse.Status)
		logx.Errorf("客户端 请求失败 Client PostFile Server error:%+v", err)
	}
	return res, err
}