// Package safediagnostic produces bounded, privacy-safe summaries of external
// process failures. Callers must sanitize before writing diagnostics to logs.
package safediagnostic

import (
	"net/url"
	"regexp"
	"strings"
)

var (
	ansi       = regexp.MustCompile(`\x1b\[[0-?]*[ -/]*[@-~]`)
	urlValue   = regexp.MustCompile(`(?i)https?://[^\s"'<>]+`)
	jsonSecret = regexp.MustCompile(`(?i)("(?:authorization|api[_-]?key|x-api-key|token|secret|password)"\s*:\s*)"(?:\\.|[^"\\])*"`)
	secret     = regexp.MustCompile(`(?im)(authorization|api[_-]?key|x-api-key|token|secret|password)(\s*[:=]\s*)("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|bearer\s+[^\s,}]+|[^\s,}]+)`)
	bearer     = regexp.MustCompile(`(?i)bearer\s+[^\s,}]+`)
	openAIKey  = regexp.MustCompile(`\bsk-[A-Za-z0-9_*-]{8,}\b`)
)

// Sanitize strips terminal control codes and secrets, removes URL credentials,
// queries, and fragments, flattens whitespace, and truncates by rune count.
func Sanitize(raw string, maxRunes int) string {
	value := ansi.ReplaceAllString(raw, "")
	value = jsonSecret.ReplaceAllString(value, `${1}"<redacted>"`)
	// Strip URL userinfo/query/fragment before generic key=value redaction so a
	// query token cannot leave a redaction marker appended to the endpoint.
	value = urlValue.ReplaceAllStringFunc(value, sanitizeURL)
	value = secret.ReplaceAllString(value, `${1}${2}<redacted>`)
	value = bearer.ReplaceAllString(value, "Bearer <redacted>")
	value = openAIKey.ReplaceAllString(value, "<redacted>")
	value = strings.Join(strings.Fields(value), " ")
	if maxRunes <= 0 {
		return value
	}
	runes := []rune(value)
	if len(runes) > maxRunes {
		return string(runes[:maxRunes]) + "… [display truncated]"
	}
	return value
}

func sanitizeURL(raw string) string {
	parsed, err := url.Parse(raw)
	if err != nil {
		return "<redacted-url>"
	}
	parsed.User = nil
	parsed.RawQuery = ""
	parsed.ForceQuery = false
	parsed.Fragment = ""
	return parsed.String()
}
