package vkpay

import (
	"crypto/md5"
	"encoding/hex"
	"maps"
	"sort"
	"strings"
	"testing"
)

// vkSig computes a valid VK signature the way VK does, for the fixtures (sig excluded, sorted
// key=value concatenation, secret appended, MD5 hex).
func vkSig(params map[string]string, secret string) string {
	keys := make([]string, 0, len(params))
	for k := range params {
		if k == "sig" {
			continue
		}
		keys = append(keys, k)
	}
	sort.Strings(keys)
	var b strings.Builder
	for _, k := range keys {
		b.WriteString(k + "=" + params[k])
	}
	b.WriteString(secret)
	sum := md5.Sum([]byte(b.String()))
	return hex.EncodeToString(sum[:])
}

func clone(m map[string]string) map[string]string {
	out := make(map[string]string, len(m))
	maps.Copy(out, m)
	return out
}

func TestVerify(t *testing.T) {
	const secret = "app_secret"
	base := map[string]string{
		"notification_type": "order_status_change",
		"app_id":            "123",
		"user_id":           "456",
		"receiver_id":       "456",
		"order_id":          "789",
		"date":              "1700000000",
		"status":            "chargeable",
		"item":              "019f47a0-6f9e-7000-8000-000000000000",
		"item_price":        "10",
	}
	valid := clone(base)
	// VK sends the digest uppercase; the verifier must accept it case-insensitively.
	valid["sig"] = strings.ToUpper(vkSig(base, secret))

	if !Verify(valid, secret) {
		t.Fatal("valid VK signature rejected")
	}

	tampered := clone(valid)
	tampered["item_price"] = "1"
	if Verify(tampered, secret) {
		t.Error("accepted a tampered amount")
	}

	if Verify(valid, "wrong-secret") {
		t.Error("accepted under the wrong secret")
	}

	noSig := clone(valid)
	delete(noSig, "sig")
	if Verify(noSig, secret) {
		t.Error("accepted a callback with no signature")
	}
}
