package request

import (
	"context"
	"github.com/cloudreve/Cloudreve/v4/pkg/auth"
	"github.com/cloudreve/Cloudreve/v4/pkg/logging"
	"net/http"
	"net/url"
	"strings"
	"time"
)

// Option 发送请求的额外设置
type Option interface {
	apply(*options)
}

type options struct {
	timeout           time.Duration
	header            http.Header
	sign              auth.Auth
	signTTL           int64
	ctx               context.Context
	contentLength     int64
	masterMeta        bool
	siteID            string
	siteURL           string
	endpoint          *url.URL
	slaveNodeID       int
	tpsLimiterToken   string
	tps               float64
	tpsBurst          int
	logger            logging.Logger
	withCorrelationID bool
	cookieJar         http.CookieJar
	transport         *http.Transport
}

type optionFunc func(*options)

func (f optionFunc) apply(o *options) {
	f(o)
}

func newDefaultOption() *options {
	return &options{
		header:        http.Header{},
		timeout:       0,
		contentLength: -1,
		ctx:           context.Background(),
	}
}

func (o *options) clone() options {
	newOptions := *o
	newOptions.header = o.header.Clone()
	return newOptions
}

// WithTransport 设置请求Transport
func WithTransport(transport *http.Transport) Option {
	return optionFunc(func(o *options) {
		o.transport = transport
	})
}

// WithTimeout 设置请求超时
func WithTimeout(t time.Duration) Option {
	return optionFunc(func(o *options) {
		o.timeout = t
	})
}

// WithContext 设置请求上下文
func WithContext(c context.Context) Option {
	return optionFunc(func(o *options) {
		o.ctx = c
	})
}

// WithCredential 对请求进行签名
func WithCredential(instance auth.Auth, ttl int64) Option {
	return optionFunc(func(o *options) {
		o.sign = instance
		if ttl > 0 {
			o.signTTL = ttl
		}
	})
}

// WithHeader 设置请求Header
func WithHeader(header http.Header) Option {
	return optionFunc(func(o *options) {
		for k, v := range header {
			o.header[k] = v
		}
	})
}

// WithoutHeader 设置清除请求Header
func WithoutHeader(header []string) Option {
	return optionFunc(func(o *options) {
		for _, v := range header {
			delete(o.header, v)
		}

	})
}

// WithContentLength 设置请求大小
func WithContentLength(s int64) Option {
	return optionFunc(func(o *options) {
		o.contentLength = s
	})
}

// WithMasterMeta 请求时携带主机信息
func WithMasterMeta(siteID string, siteURL string) Option {
	return optionFunc(func(o *options) {
		o.masterMeta = true
		o.siteID = siteID
		o.siteURL = siteURL
	})
}

// WithSlaveMeta set slave node ID in master's request header
func WithSlaveMeta(s int) Option {
	return optionFunc(func(o *options) {
		o.slaveNodeID = s
	})
}

// Endpoint 使用同一的请求Endpoint
func WithEndpoint(endpoint string) Option {
	if !strings.HasSuffix(endpoint, "/") {
		endpoint += "/"
	}

	endpointURL, _ := url.Parse(endpoint)
	return optionFunc(func(o *options) {
		o.endpoint = endpointURL
	})
}

// WithTPSLimit 请求时使用全局流量限制
func WithTPSLimit(token string, tps float64, burst int) Option {
	return optionFunc(func(o *options) {
		o.tpsLimiterToken = token
		o.tps = tps
		if burst < 1 {
			burst = 1
		}
		o.tpsBurst = burst
	})
}

// WithLogger set logger for logging requests
func WithLogger(logger logging.Logger) Option {
	return optionFunc(func(o *options) {
		o.logger = logger
	})
}

// WithCorrelationID set correlation ID for logging requests
func WithCorrelationID() Option {
	return optionFunc(func(o *options) {
		o.withCorrelationID = true
	})
}

// WithCookieJar set cookie jar for request
func WithCookieJar(jar http.CookieJar) Option {
	return optionFunc(func(o *options) {
		o.cookieJar = jar
	})
}
