package httprange

import (
	
	
	
	
	

	
)

const (
	httpHeaderIfMatch           = "If-Match"
	httpHeaderIfUnmodifiedSince = "If-Unmodified-Since"
)

// HTTPValidatorBuilder builds HTTP clients that wraps [httpclient.Client] with
// resource state validation.
type HTTPValidatorBuilder interface {
	Build(context.Context, HTTPMetadataProvider, httpclient.Client) (httpclient.Client, error)
}

// HTTPStrongValidatorBuilder implements [HTTPValidatorBuilder] using strong
// validators. It prefers strong ETags over Last-Modified dates for validation.
type HTTPStrongValidatorBuilder struct {
	// UseLastModified controls whether to use Last-Modified dates when
	// no strong ETag is available. When false, returns an error if no
	// strong ETag is available.
	UseLastModified bool
}

// Build creates a validator client that adds either If-Match or If-Unmodified-Since
// headers to requests, depending on the available metadata.
//
// It returns an error if no applicable validator is available.
func ( *HTTPStrongValidatorBuilder) ( context.Context,  HTTPMetadataProvider,  httpclient.Client) (httpclient.Client, error) {
	switch  := .Provide(); {
	case .ETag != "" && !strings.HasPrefix(.ETag, weakETagPrefix):
		return &HTTPStrongValidator{
			Client: ,
			Precondition: http.Header{
				httpHeaderIfMatch: {.ETag},
			},
			ETag: .ETag,
		}, nil
	case .UseLastModified && !.LastModified.IsZero() && .Date.After(.LastModified):
		 := .LastModified.UTC().Format(http.TimeFormat)
		return &HTTPStrongValidator{
			Client: ,
			Precondition: http.Header{
				httpHeaderIfUnmodifiedSince: {},
			},
			LastModified: .LastModified,
		}, nil
	default:
		return nil, errNoApplicableValidator
	}
}

// HTTPStrongValidator is an [httpclient.Client] that adds precondition headers
// to requests and validates that the resource hasn’t changed in responses.
type HTTPStrongValidator struct {
	// Client is the HTTP client instance to use.
	Client httpclient.Client

	// Precondition contains headers to add to requests.
	Precondition http.Header

	// ETag is the expected entity tag in responses.
	ETag string

	// LastModified is the expected Last-Modified time in responses.
	LastModified time.Time
}

// Do executes a conditional HTTP request and checks the response to ensure the
// resource hasn’t changed.
func ( *HTTPStrongValidator) ( *http.Request) (*http.Response, error) {
	.Header = setHeader(.Header, .Precondition)

	,  := .Client.Do()
	if  != nil {
		return nil, 
	}

	if  := .checkValidator();  != nil {
		_ = .Body.Close()
		return nil, &HTTPResponseError{
			Response: ,
			cause:    ,
		}
	}

	return , nil
}

func ( *HTTPStrongValidator) ( *http.Response) error {
	switch {
	case .ETag != "":
		,  := parseETagOrZero(.Header)
		if  != nil {
			return 
		}
		if .ETag !=  {
			return fmt.Errorf(
				"httprange: ETag validator changed from %q to %q",
				.ETag, ,
			)
		}
	case !.LastModified.IsZero():
		 := .Header.Get(httpHeaderLastModified)
		,  := http.ParseTime()
		if  != nil {
			return 
		}
		if !.Equal(.LastModified) {
			return fmt.Errorf(
				"httprange: Last-Modified validator changed from %q to %q",
				.LastModified, ,
			)
		}
	}
	return nil
}