package telemetrymeta

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

	"github.com/go-chi/chi/v5"

	"github.com/aoagents/agent-orchestrator/backend/internal/httpd/apierr"
)

// ErrorKindAndCode extracts a telemetry-safe error category and optional code.
func ErrorKindAndCode(err error) (kind, code string) {
	kind = "internal"
	var apiErr *apierr.Error
	if errors.As(err, &apiErr) {
		return ErrorKind(apiErr.Kind), apiErr.Code
	}
	return kind, ""
}

// ErrorKind maps API error kinds to coarse telemetry-safe categories.
func ErrorKind(kind apierr.Kind) string {
	switch kind {
	case apierr.KindInvalid:
		return "invalid"
	case apierr.KindNotFound:
		return "not_found"
	case apierr.KindConflict:
		return "conflict"
	default:
		return "internal"
	}
}

// PanicKind classifies panic payloads without exporting their raw contents.
func PanicKind(rec any) string {
	switch rec.(type) {
	case error:
		return "error"
	case string:
		return "string"
	default:
		return "other"
	}
}

// StatusFamily returns a telemetry-friendly HTTP status bucket like 5xx.
func StatusFamily(status int) string {
	if status < 100 || status > 999 {
		return "unknown"
	}
	return fmt.Sprintf("%dxx", status/100)
}

// RoutePattern returns the chi route template when available, else the URL path.
func RoutePattern(r *http.Request) string {
	if r == nil {
		return ""
	}
	if rc := chi.RouteContext(r.Context()); rc != nil {
		if pattern := strings.TrimSpace(rc.RoutePattern()); pattern != "" {
			return pattern
		}
	}
	if r.URL == nil {
		return ""
	}
	return r.URL.Path
}

// Fingerprint returns a short stable digest for grouping similar failures.
func Fingerprint(parts ...string) string {
	h := sha256.New()
	for _, part := range parts {
		part = strings.TrimSpace(part)
		if part == "" {
			continue
		}
		_, _ = h.Write([]byte(part))
		_, _ = h.Write([]byte{0})
	}
	sum := hex.EncodeToString(h.Sum(nil))
	if len(sum) > 16 {
		return sum[:16]
	}
	return sum
}
