package binding

import (
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"sort"
)

const boundRequestHashDomain = "agentteam.extension.bound-request/v1\x00"

type boundRequestHashHeader struct {
	Name   string   `json:"name"`
	Values []string `json:"values"`
}

type boundRequestHashPayload struct {
	Method   string                   `json:"method"`
	URL      string                   `json:"url"`
	Headers  []boundRequestHashHeader `json:"headers"`
	Body     json.RawMessage          `json:"body,omitempty"`
	Response ResponsePolicy           `json:"response"`
}

func hashBoundRequest(bound BoundRequest) (string, error) {
	names := make([]string, 0, len(bound.Headers))
	for name := range bound.Headers {
		names = append(names, name)
	}
	sort.Strings(names)
	headers := make([]boundRequestHashHeader, 0, len(names))
	for _, name := range names {
		headers = append(headers, boundRequestHashHeader{
			Name: name, Values: append([]string(nil), bound.Headers.Values(name)...),
		})
	}
	payload := boundRequestHashPayload{
		Method: bound.Method, Headers: headers, Response: bound.ResponsePolicy,
	}
	if bound.URL != nil {
		payload.URL = bound.URL.String()
	}
	if len(bound.Body) > 0 {
		payload.Body = append(json.RawMessage(nil), bound.Body...)
	}
	encoded, err := json.Marshal(payload)
	if err != nil {
		return "", err
	}
	sum := sha256.Sum256(append([]byte(boundRequestHashDomain), encoded...))
	return "sha256:" + hex.EncodeToString(sum[:]), nil
}
