// Required namespaces: System, System.Linq, System.Text.RegularExpressions

using System.Text.RegularExpressions;

namespace aeqw89.tools.Publish;

public enum RemoteOs { Windows, Unix }

public static partial class RemotePath
{
    public static string Combine(RemoteOs os, params string[] parts)
    {
        if (parts == null || parts.Length == 0) return string.Empty;

        // Normalize null/empty segments and trim whitespace
        var cleaned = parts.Where(p => !string.IsNullOrWhiteSpace(p))
                           .Select(p => p.Trim())
                           .ToArray();
        if (cleaned.Length == 0) return string.Empty;

        return os == RemoteOs.Windows
            ? CombineWindows(cleaned)
            : CombineUnix(cleaned);
    }

    private static string CombineUnix(string[] parts)
    {
        // Keep a single leading '/' if the first segment is rooted
        bool rooted = parts[0].StartsWith("/", StringComparison.Ordinal);
        var body = parts.Select((p, i) =>
                    {
                        var s = p.Replace("\\", "/");
                        // Trim both ends except preserve leading '/' only for first segment
                        if (i == 0)
                            return s.TrimEnd('/');
                        return s.Trim('/'); // internal segments never carry separators
                    })
                    .Where(s => s.Length > 0)
                    .ToArray();

        var joined = string.Join("/", body);
        return rooted ? (joined.StartsWith("/") ? joined : "/" + joined) : joined;
    }

    private static string CombineWindows(string[] parts)
    {
        // Windows separators are backslashes for cmd.exe/PowerShell paths.
        // Preserve drive letters like "C:" and UNC roots like "\\server".
        var first = parts[0].Replace("/", "\\").Trim();
        var rest = parts.Skip(1)
                        .Select(p => p.Replace("/", "\\").Trim('\\'))
                        .Where(s => s.Length > 0)
                        .ToArray();

        // Detect UNC root (\\server\share...) or device prefix (\\?\ or \\.\)
        bool isUncOrDevice = first.StartsWith(@"\\", StringComparison.Ordinal);
        bool isDrive = IsDrive().IsMatch(first);

        if (isUncOrDevice)
        {
            // Keep exactly two leading backslashes; trim trailing ones
            first = @"\\" + first.TrimStart('\\').TrimEnd('\\');
        }
        else if (isDrive)
        {
            // Normalize "C:" or "C:\" to "C:\"
            first = first.Length == 2 ? first + "\\" : first;
        }
        else
        {
            // For relative first segment, strip surrounding slashes
            first = first.Trim('\\');
        }

        string joined = rest.Length > 0
            ? first + (first.EndsWith("\\") ? "" : "\\") + string.Join("\\", rest)
            : first;

        // Collapse any accidental doubles that can appear from user input (but keep UNC prefix)
        if (!joined.StartsWith(@"\\"))
            joined = Collapse().Replace(joined, @"\");

        return joined;
    }

    [System.Text.RegularExpressions.GeneratedRegex(@"^[A-Za-z]:\\?$")]
    private static partial System.Text.RegularExpressions.Regex IsDrive();
    [GeneratedRegex(@"\\{2,}")]
    private static partial Regex Collapse();
}
