package providers

import (
	"encoding/json"
	"regexp"
	"strings"
)

var providerPANPattern = regexp.MustCompile(`\b(?:\d[ -]?){13,19}\b`)

func RedactJSONValue(value any) json.RawMessage {
	if value == nil {
		return json.RawMessage(`{}`)
	}
	raw, err := json.Marshal(value)
	if err != nil {
		return json.RawMessage(`{"redaction_error":"marshal_failed"}`)
	}
	return RedactJSON(raw)
}

func RedactJSON(raw []byte) json.RawMessage {
	if len(raw) == 0 {
		return json.RawMessage(`{}`)
	}
	var value any
	if err := json.Unmarshal(raw, &value); err == nil {
		redacted := redactAny(value)
		encoded, err := json.Marshal(redacted)
		if err == nil {
			return encoded
		}
	}
	text := providerPANPattern.ReplaceAllString(string(raw), "[REDACTED_CARD]")
	encoded, _ := json.Marshal(map[string]string{"raw": text})
	return encoded
}

func redactAny(value any) any {
	switch typed := value.(type) {
	case map[string]any:
		out := make(map[string]any, len(typed))
		for key, nested := range typed {
			if sensitiveProviderKey(key) {
				out[key] = "[REDACTED]"
				continue
			}
			out[key] = redactAny(nested)
		}
		return out
	case []any:
		out := make([]any, 0, len(typed))
		for _, nested := range typed {
			out = append(out, redactAny(nested))
		}
		return out
	case string:
		return providerPANPattern.ReplaceAllString(typed, "[REDACTED_CARD]")
	default:
		return value
	}
}

func sensitiveProviderKey(key string) bool {
	key = strings.ToLower(strings.TrimSpace(key))
	fragments := []string{
		"password",
		"secret",
		"token",
		"authorization",
		"cookie",
		"cvv",
		"pan",
		"card_number",
		"private_key",
		"api_key",
		"webhook",
		"mfa",
		"document_number",
		"date_of_birth",
		"dob",
		"legal_name",
		"address",
		"email",
		"phone",
	}
	for _, fragment := range fragments {
		if strings.Contains(key, fragment) {
			return true
		}
	}
	return false
}
