package adapter

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"strconv"
	"testing"
	"time"
)

// sign reproduces alertstore's sender format so these tests fail if either side
// drifts from the shared scheme.
func sign(secret string, ts int64, body []byte) string {
	mac := hmac.New(sha256.New, []byte(secret))
	mac.Write([]byte(strconv.FormatInt(ts, 10)))
	mac.Write([]byte("."))
	mac.Write(body)
	return "t=" + strconv.FormatInt(ts, 10) + ",v1=" + hex.EncodeToString(mac.Sum(nil))
}

func TestValidSignature(t *testing.T) {
	const secret = "s3cr3t"
	now := time.Unix(1_700_000_000, 0)
	body := []byte(`{"alert_id":"ALT-1","run_id":7}`)

	if !validSignature(secret, sign(secret, now.Unix(), body), body, now) {
		t.Fatal("a freshly signed body should verify")
	}

	cases := map[string]struct {
		header string
		body   []byte
	}{
		"tampered body":    {sign(secret, now.Unix(), body), []byte(`{"alert_id":"ALT-2","run_id":7}`)},
		"wrong secret":     {sign("other", now.Unix(), body), body},
		"stale timestamp":  {sign(secret, now.Add(-10*time.Minute).Unix(), body), body},
		"future timestamp": {sign(secret, now.Add(10*time.Minute).Unix(), body), body},
		"missing v1":       {"t=" + strconv.FormatInt(now.Unix(), 10), body},
		"missing t":        {"v1=deadbeef", body},
		"not hex":          {"t=" + strconv.FormatInt(now.Unix(), 10) + ",v1=zz", body},
		"empty":            {"", body},
	}
	for name, c := range cases {
		t.Run(name, func(t *testing.T) {
			if validSignature(secret, c.header, c.body, now) {
				t.Errorf("%s should not verify", name)
			}
		})
	}
}

func TestValidSignatureWithinTolerance(t *testing.T) {
	const secret = "s3cr3t"
	now := time.Unix(1_700_000_000, 0)
	body := []byte(`{"alert_id":"ALT-1"}`)
	// Signed a minute ago, still inside the freshness window.
	if !validSignature(secret, sign(secret, now.Add(-time.Minute).Unix(), body), body, now) {
		t.Fatal("a signature a minute old should still verify")
	}
}
