package safepath

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

// IsDir returns true if the filePath ends with a slash.
// Empty string is considered a directory.
func IsDir(filePath string) bool {
	if filePath == "" || filePath == "." {
		return true
	}

	return strings.HasSuffix(filePath, "/")
}

// Dir behaves exactly as path.Dir, but returns "" for the root directory.
// and returns a trailing slash for all other directories.
func Dir(filePath string) string {
	if filePath == "" {
		return ""
	}

	// Trim trailing slash before getting the directory
	cleanPath := strings.TrimSuffix(filePath, "/")
	dir := path.Dir(cleanPath)
	if dir == "." || dir == "/" {
		return ""
	}

	return dir + "/"
}

// InDir returns true if the filePath is a subdirectory of the given directory.
func InDir(filePath, dir string) bool {
	return strings.HasPrefix(filePath, dir)
}

// EnsureTrailingSlash returns the path with a trailing slash appended if it
// doesn't already have one. This is useful for marking paths as directories.
// To keep compatibility with the functions in this package, the "root" directory
// (which can be represented as "" or "." or "/") is returned as "".
func EnsureTrailingSlash(filePath string) string {
	if filePath == "" || filePath == "." || filePath == "/" {
		return ""
	}

	if strings.HasSuffix(filePath, "/") {
		return filePath
	}

	return filePath + "/"
}

// RelativeTo returns the relative path of the filePath to the given directory.
// It handles cases where either filePath or dir have leading or trailing slashes.
func RelativeTo(filePath, dir string) (string, error) {
	if dir == "/" || dir == "" {
		return filePath, nil
	}

	// Normalize paths by trimming leading and trailing slashes
	normalizedDir := strings.Trim(dir, "/")
	if normalizedDir != "" {
		normalizedDir += "/"
	}

	normalizedPath := strings.TrimPrefix(filePath, "/")

	// Check if the normalized path is in the normalized directory
	if !strings.HasPrefix(normalizedPath, normalizedDir) {
		return "", fmt.Errorf("filePath is not a subdirectory of dir")
	}

	// Get the relative path by trimming the directory prefix
	relativePath := strings.TrimPrefix(normalizedPath, normalizedDir)

	return relativePath, nil
}
