// (c) 2012-2020 by Taxnexus, Inc.
// All rights reserved worldwide.
// Proprietary product; unlicensed use is not allowed

package members_client

import (
	"errors"
	"fmt"

	"github.com/go-openapi/runtime"
	"github.com/go-openapi/strfmt"
)

const maxCredentialLength = 8192

// NewMembersCompoundAuth returns the auth writer required by governed Members
// operations: a service API key plus the active human kvSession cookie.
//
// Credential values are retained only inside the returned closure. Validation
// errors identify the invalid field without including its value.
func NewMembersCompoundAuth(apiKey, sessionToken string) (runtime.ClientAuthInfoWriter, error) {
	if err := validateHeaderCredential("Members API key", apiKey); err != nil {
		return nil, err
	}
	if err := validateCookieCredential("Members session token", sessionToken); err != nil {
		return nil, err
	}

	return runtime.ClientAuthInfoWriterFunc(func(request runtime.ClientRequest, _ strfmt.Registry) error {
		if err := request.SetHeaderParam("X-API-Key", apiKey); err != nil {
			return fmt.Errorf("set Members API key header: %w", err)
		}
		if err := request.SetHeaderParam("Cookie", "kvSession="+sessionToken); err != nil {
			return fmt.Errorf("set Members session cookie: %w", err)
		}
		return nil
	}), nil
}

func validateHeaderCredential(name, value string) error {
	if value == "" {
		return fmt.Errorf("%s is required", name)
	}
	if len(value) > maxCredentialLength {
		return fmt.Errorf("%s exceeds the maximum length", name)
	}
	for index := 0; index < len(value); index++ {
		if value[index] < 0x21 || value[index] > 0x7e {
			return fmt.Errorf("%s contains an invalid header byte", name)
		}
	}
	return nil
}

func validateCookieCredential(name, value string) error {
	if err := validateHeaderCredential(name, value); err != nil {
		return err
	}
	for index := 0; index < len(value); index++ {
		character := value[index]
		if character == '"' || character == ',' || character == ';' || character == '\\' {
			return errors.New(name + " contains an invalid cookie byte")
		}
	}
	return nil
}
