// Package authrace is a controlled HTTP authorization and concurrency regression
// harness. It cannot scan arbitrary hosts: the only target is its local test server.
package authrace

import (
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"strings"
	"sync"
)

type Refund struct {
	Tenant    string `json:"tenant"`
	Operation string `json:"operation_id"`
	Amount    int    `json:"amount"`
}
type Result struct {
	Granted bool   `json:"granted"`
	Reason  string `json:"reason"`
	Balance int    `json:"balance"`
}
type Handler struct {
	mu         sync.Mutex
	balance    map[string]int
	ledger     map[string]string
	vulnerable bool
}

func New(vulnerable bool) *Handler {
	return &Handler{
		balance:    map[string]int{"alpha": 0, "beta": 0},
		ledger:     map[string]string{},
		vulnerable: vulnerable,
	}
}
func decodeRequest(r *http.Request) (Refund, error) {
	var x Refund
	if r.Method != http.MethodPost || r.URL.Path != "/v1/refund" {
		return x, errors.New("invalid_route")
	}
	dec := json.NewDecoder(http.MaxBytesReader(nil, r.Body, 2048))
	dec.DisallowUnknownFields()
	if err := dec.Decode(&x); err != nil {
		return x, errors.New("invalid_json")
	}
	if x.Tenant != "alpha" && x.Tenant != "beta" {
		return x, errors.New("invalid_tenant")
	}
	if len(x.Operation) < 8 || len(x.Operation) > 80 || x.Amount < 1 || x.Amount > 100 {
		return x, errors.New("invalid_claim")
	}
	return x, nil
}
func fingerprint(x Refund) string {
	data := fmt.Sprintf("%s|%s|%d", x.Tenant, x.Operation, x.Amount)
	sum := sha256.Sum256([]byte(data))
	return hex.EncodeToString(sum[:])
}
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Cache-Control", "no-store")
	request, err := decodeRequest(r)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		_ = json.NewEncoder(w).Encode(Result{Reason: err.Error()})
		return
	}
	// Synthetic identity fixture. A real API must verify signature, issuer, audience,
	// expiry and session state; this intentionally models an already-verified principal.
	principal := strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ")
	if principal != "alpha" && principal != "beta" {
		w.WriteHeader(http.StatusUnauthorized)
		_ = json.NewEncoder(w).Encode(Result{Reason: "unauthenticated"})
		return
	}
	if h.vulnerable {
		// Deliberately vulnerable fixture: trusts request tenant and replays mutations.
		h.mu.Lock()
		h.balance[request.Tenant] += request.Amount
		balance := h.balance[request.Tenant]
		h.mu.Unlock()
		w.WriteHeader(http.StatusOK)
		_ = json.NewEncoder(w).Encode(Result{Granted: true, Reason: "vulnerable_mutation", Balance: balance})
		return
	}
	if request.Tenant != principal {
		w.WriteHeader(http.StatusForbidden)
		_ = json.NewEncoder(w).Encode(Result{Reason: "tenant_scope_denied"})
		return
	}
	key := principal + "|" + request.Operation
	digest := fingerprint(request)
	h.mu.Lock()
	defer h.mu.Unlock()
	if previous, exists := h.ledger[key]; exists {
		if previous != digest {
			w.WriteHeader(http.StatusConflict)
			_ = json.NewEncoder(w).Encode(Result{Reason: "operation_fingerprint_conflict", Balance: h.balance[principal]})
			return
		}
		w.WriteHeader(http.StatusOK)
		_ = json.NewEncoder(w).Encode(Result{Granted: false, Reason: "duplicate_suppressed", Balance: h.balance[principal]})
		return
	}
	// Atomic claim and side effect. Real storage needs a DB transaction and
	// an outbox to reconcile irreversible downstream effects.
	h.ledger[key] = digest
	h.balance[principal] += request.Amount
	w.WriteHeader(http.StatusOK)
	_ = json.NewEncoder(w).Encode(Result{Granted: true, Reason: "applied_once", Balance: h.balance[principal]})
}
func (h *Handler) Balance(tenant string) int {
	h.mu.Lock()
	defer h.mu.Unlock()
	return h.balance[tenant]
}
