// Copyright 2025 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package files

import (
	"fmt"
	"path"
	"strings"
)

// This is keep in for the case that in the future, parts of the filenames need sanitizing
// var fileNameComponentSanitizeRegexp = regexp.MustCompile(`(?i)[<>:\"/\\|?*\x{0000}-\x{001F}]|^(con|prn|aux|nul|com\d|lpt\d)$`)

// SanitizePath cleans and validates a file path
func SanitizePath(inputPath string) (string, error) {
	// Normalize path separators
	s := strings.ReplaceAll(inputPath, "\\", "/")

	// We don't want a / or \\ as the beginning of a path
	if strings.HasPrefix(inputPath, "/") {
		return "", fmt.Errorf("path starts with / : %s", inputPath)
	}

	// Make path temporarily absolute to ensure proper cleaning of all components
	temp := "/" + s

	// Clean the path (this will properly handle ../.. components when absolute)
	temp = path.Clean(temp)

	// Remove the leading / to make it relative again
	s = strings.TrimPrefix(temp, "/")

	// If the cleaned path is empty or becomes root, it's invalid
	if s == "" {
		return "", fmt.Errorf("path resolves to root or becomes empty after cleaning")
	}

	// Split the path components
	pathComponents := strings.Split(s, "/")
	// Sanitize each path component
	var sanitizedComponents []string
	for _, component := range pathComponents {
		// Alternaitve option if parts of the filenames need sanitizing (Trim whitespace and apply regex sanitization)
		// sanitizedComponent := strings.TrimSpace(fileNameComponentSanitizeRegexp.ReplaceAllString(component, "_"))

		// Trim whitespace
		sanitizedComponent := strings.TrimSpace(component)

		// Skip empty components after sanitization
		if sanitizedComponent != "" {
			sanitizedComponents = append(sanitizedComponents, sanitizedComponent)
		}
	}
	// Check if we have any components left after sanitization
	if len(sanitizedComponents) == 0 {
		return "", fmt.Errorf("path became empty after sanitization")
	}
	// Reconstruct the path
	reconstructedPath := path.Join(sanitizedComponents...)
	return reconstructedPath, nil
}
