package proto

import (
	"fmt"
	"net/http"
	"strings"
)

type SigInput struct {
	Proto        string
	Method       string
	PathQuery    string
	SenderKID    string
	RecipientKID string
	TimestampMs  string
	ExpiryMs     string
	Nonce        string
	OrigCT       string
	BodySHA256   string
	Extra        map[string]string
}

func BuildSigInputFromRequest(r *http.Request, bodySHA256 string) SigInput {
	get := func(k string) string { return r.Header.Get(k) }
	return SigInput{
		Proto:        get(HeaderProto),
		Method:       strings.ToUpper(r.Method),
		PathQuery:    r.URL.RequestURI(),
		SenderKID:    get(HeaderSenderKID),
		RecipientKID: get(HeaderRecipientKID),
		TimestampMs:  get(HeaderTimestampMs),
		ExpiryMs:     get(HeaderExpiryMs),
		Nonce:        get(HeaderNonce),
		OrigCT:       get(HeaderOrigCT),
		BodySHA256:   bodySHA256,
	}
}

func (s SigInput) CanonicalString() string {
	// Use a fixed order and lowercase header names.
	// No reliance on JSON canonicalization.
	lines := []string{
		s.Proto,
		s.Method,
		s.PathQuery,
		fmt.Sprintf("%s:%s", strings.ToLower(HeaderSenderKID), s.SenderKID),
		fmt.Sprintf("%s:%s", strings.ToLower(HeaderRecipientKID), s.RecipientKID),
		fmt.Sprintf("%s:%s", strings.ToLower(HeaderTimestampMs), s.TimestampMs),
		fmt.Sprintf("%s:%s", strings.ToLower(HeaderExpiryMs), s.ExpiryMs),
		fmt.Sprintf("%s:%s", strings.ToLower(HeaderNonce), s.Nonce),
		fmt.Sprintf("%s:%s", strings.ToLower(HeaderOrigCT), s.OrigCT),
		fmt.Sprintf("body-sha256:%s", s.BodySHA256),
	}
	return strings.Join(lines, "\n")
}

func (s SigInput) AADString() string {
	// Bind encryption to request context; exclude body hash.
	lines := []string{
		s.Proto,
		s.Method,
		s.PathQuery,
		s.SenderKID,
		s.RecipientKID,
		s.TimestampMs,
		s.ExpiryMs,
		s.Nonce,
		s.OrigCT,
	}
	return strings.Join(lines, "\n")
}
