package main

import (
	"encoding/json"
	"errors"
	"io"
	"log/slog"
	"net/http"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

const maxCallbackBodyBytes = 1 << 20

type collector struct {
	mu         sync.Mutex
	deliveries int64
	duplicates int64
	invalid    int64
	seen       map[string]int
}

func main() {
	address := strings.TrimSpace(os.Getenv("HTTP_ADDR"))
	if address == "" {
		address = ":8091"
	}
	state := &collector{seen: map[string]int{}}
	mux := http.NewServeMux()
	mux.HandleFunc("GET /healthz", func(w http.ResponseWriter, _ *http.Request) {
		writeJSON(w, http.StatusOK, map[string]any{"ok": true})
	})
	mux.HandleFunc("GET /report", state.report)
	mux.HandleFunc("POST /callbacks", state.callback)
	server := &http.Server{
		Addr:              address,
		Handler:           mux,
		ReadHeaderTimeout: 10 * time.Second,
	}
	slog.Info("acceptance callback collector started", "address", address)
	if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
		slog.Error("acceptance callback collector stopped", "error", err)
		os.Exit(1)
	}
}

func (c *collector) callback(w http.ResponseWriter, request *http.Request) {
	body, err := io.ReadAll(io.LimitReader(request.Body, maxCallbackBodyBytes+1))
	if err != nil || len(body) > maxCallbackBodyBytes {
		c.recordInvalid()
		writeJSON(w, http.StatusBadRequest, map[string]any{"error": "invalid callback body"})
		return
	}
	decoder := json.NewDecoder(strings.NewReader(string(body)))
	decoder.UseNumber()
	var payload map[string]any
	if err := decoder.Decode(&payload); err != nil {
		c.recordInvalid()
		writeJSON(w, http.StatusBadRequest, map[string]any{"error": "invalid callback JSON"})
		return
	}
	taskID := strings.TrimSpace(stringValue(payload["taskId"]))
	seq, _ := strconv.ParseInt(stringValue(payload["seq"]), 10, 64)
	idempotency := strings.TrimSpace(request.Header.Get("Idempotency-Key"))
	expected := taskID + ":" + strconv.FormatInt(seq, 10)
	if taskID == "" || seq <= 0 || idempotency != expected {
		c.recordInvalid()
		writeJSON(w, http.StatusBadRequest, map[string]any{"error": "callback identity is invalid"})
		return
	}
	c.mu.Lock()
	c.deliveries++
	c.seen[expected]++
	if c.seen[expected] > 1 {
		c.duplicates++
	}
	c.mu.Unlock()
	writeJSON(w, http.StatusOK, map[string]any{"ok": true})
}

func (c *collector) report(w http.ResponseWriter, _ *http.Request) {
	c.mu.Lock()
	report := map[string]any{
		"schemaVersion": "acceptance-callback-report/v1",
		"deliveries":    c.deliveries,
		"duplicates":    c.duplicates,
		"invalid":       c.invalid,
		"uniqueEvents":  len(c.seen),
	}
	c.mu.Unlock()
	writeJSON(w, http.StatusOK, report)
}

func (c *collector) recordInvalid() {
	c.mu.Lock()
	c.invalid++
	c.mu.Unlock()
}

func stringValue(value any) string {
	switch typed := value.(type) {
	case string:
		return typed
	case json.Number:
		return typed.String()
	case float64:
		return strconv.FormatFloat(typed, 'f', -1, 64)
	default:
		return ""
	}
}

func writeJSON(w http.ResponseWriter, status int, value any) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)
	_ = json.NewEncoder(w).Encode(value)
}
