package handlers

import (
	"encoding/json"
	"log/slog"
	"net/http"
	"strings"
	"unicode/utf8"

	"github.com/google/uuid"
)

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

func writeError(w http.ResponseWriter, status int, msg string) {
	writeJSON(w, status, map[string]string{"error": msg})
}

// internalError logs the real error and returns a generic message to the client.
func internalError(w http.ResponseWriter, msg string, err error) {
	slog.Error(msg, "error", err)
	writeError(w, http.StatusInternalServerError, "internal error")
}

// parsePathUUID extracts a UUID from the URL path using PathValue
func parsePathUUID(r *http.Request, key string) (uuid.UUID, error) {
	return uuid.Parse(r.PathValue(key))
}

// parseUUID parses a UUID string
func parseUUID(s string) (uuid.UUID, error) {
	return uuid.Parse(s)
}

// --- Input validation helpers ---

const (
	maxTitleLen       = 500
	maxDescriptionLen = 10000
	maxCaseNumberLen  = 100
	maxSearchLen      = 200
	maxPaginationLimit = 100
)

// validateStringLength checks if a string exceeds the given max length.
func validateStringLength(field, value string, maxLen int) string {
	if utf8.RuneCountInString(value) > maxLen {
		return field + " exceeds maximum length"
	}
	return ""
}

// clampPagination enforces sane pagination defaults and limits.
func clampPagination(limit, offset int) (int, int) {
	if limit <= 0 {
		limit = 20
	}
	if limit > maxPaginationLimit {
		limit = maxPaginationLimit
	}
	if offset < 0 {
		offset = 0
	}
	return limit, offset
}

// sanitizeFilename removes characters unsafe for Content-Disposition headers.
func sanitizeFilename(name string) string {
	// Remove control characters, quotes, and backslashes
	var b strings.Builder
	for _, r := range name {
		if r < 32 || r == '"' || r == '\\' || r == '/' {
			b.WriteRune('_')
		} else {
			b.WriteRune(r)
		}
	}
	return b.String()
}

// maskSettingsPassword masks the CalDAV password in tenant settings JSON before returning to clients.
func maskSettingsPassword(settings json.RawMessage) json.RawMessage {
	if len(settings) == 0 {
		return settings
	}
	var m map[string]json.RawMessage
	if err := json.Unmarshal(settings, &m); err != nil {
		return settings
	}
	caldavRaw, ok := m["caldav"]
	if !ok {
		return settings
	}
	var caldav map[string]json.RawMessage
	if err := json.Unmarshal(caldavRaw, &caldav); err != nil {
		return settings
	}
	if _, ok := caldav["password"]; ok {
		caldav["password"], _ = json.Marshal("********")
	}
	m["caldav"], _ = json.Marshal(caldav)
	result, _ := json.Marshal(m)
	return result
}
