package static

import (
	"fmt"
	"strings"

	"github.com/alexei/tinyforge/internal/workload/plugin"
)

// containerNameFor is the deterministic container name. Includes
// w.Name for visual continuity in `docker ps` plus the ID short for
// uniqueness.
func containerNameFor(w plugin.Workload) string {
	return fmt.Sprintf("dw-site-%s-%s", w.Name, plugin.IDShort(w))
}

// imageTagFor is the deterministic image tag — same shape as the
// container name so the linkage between an image and the workload
// that owns it stays obvious from `docker images`.
func imageTagFor(w plugin.Workload) string {
	return fmt.Sprintf("dw-site-%s-%s:latest", w.Name, plugin.IDShort(w))
}

// siteVolumeKey is the input to docker.SiteVolumeName / EnsureSiteVolume
// / RemoveSiteVolume. Composing it here (instead of building the full
// name ourselves) keeps the naming concern in one place — those docker
// helpers wrap the value with their own `tinyforge-site-...-data`
// envelope. Including idShort prevents two workloads sharing a name
// from sharing one persistent volume.
func siteVolumeKey(w plugin.Workload) string {
	return fmt.Sprintf("%s-%s", w.Name, plugin.IDShort(w))
}

// sanitizeError clamps an error string so persisting it (in
// containers.extra_json's last_error) or echoing it (via the
// outbound notification webhook) cannot leak a multi-line response
// body, an HTTP header echoing the access token, or a stack trace.
//
// Strategy:
//   - Reduce to a single line (replace any newline / tab with space).
//   - Cap to a short maxLen so a very long Gitea/GitHub error body
//     never round-trips into operator-visible state.
//   - Redact the access token verbatim if it appears in the message
//     (defense in depth — providers shouldn't echo tokens but a
//     misbehaving one could).
func sanitizeError(msg, accessToken string) string {
	if msg == "" {
		return ""
	}
	if accessToken != "" {
		msg = strings.ReplaceAll(msg, accessToken, "[REDACTED]")
	}
	// Collapse whitespace runs onto one line.
	msg = strings.Map(func(r rune) rune {
		switch r {
		case '\n', '\r', '\t':
			return ' '
		}
		return r
	}, msg)
	const maxLen = 240
	if len(msg) > maxLen {
		msg = msg[:maxLen] + "…"
	}
	return msg
}
