using Microsoft.SharePoint.Client;
using Serilog;
using SharepointToolbox.Core.Helpers;
using SharepointToolbox.Core.Models;

namespace SharepointToolbox.Services;

public class FolderStructureService : IFolderStructureService
{
    public async Task<BulkOperationSummary<string>> CreateFoldersAsync(
        ClientContext ctx,
        string libraryTitle,
        IReadOnlyList<FolderStructureRow> rows,
        IProgress<OperationProgress> progress,
        CancellationToken ct)
    {
        // Get library root folder URL
        var list = ctx.Web.Lists.GetByTitle(libraryTitle);
        ctx.Load(list, l => l.RootFolder.ServerRelativeUrl);
        await ExecuteQueryRetryHelper.ExecuteQueryRetryAsync(ctx, progress, ct);

        var baseUrl = list.RootFolder.ServerRelativeUrl.TrimEnd('/');

        // Build unique folder paths from CSV rows, sorted parent-first
        var folderPaths = BuildUniquePaths(rows);

        return await BulkOperationRunner.RunAsync(
            folderPaths,
            async (path, idx, token) =>
            {
                var fullPath = $"{baseUrl}/{path}";
                ctx.Web.Folders.Add(fullPath);
                await ExecuteQueryRetryHelper.ExecuteQueryRetryAsync(ctx, progress, token);
                Log.Information("Created folder: {Path}", fullPath);
            },
            progress,
            ct);
    }

    /// <summary>
    /// Builds unique folder paths from CSV rows, sorted parent-first to ensure
    /// parent folders are created before children.
    /// </summary>
    internal static IReadOnlyList<string> BuildUniquePaths(IReadOnlyList<FolderStructureRow> rows)
    {
        var paths = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

        foreach (var row in rows)
        {
            var parts = new[] { row.Level1, row.Level2, row.Level3, row.Level4 }
                .Where(s => !string.IsNullOrWhiteSpace(s))
                .ToArray();

            // Add each level as a path (e.g., "Admin", "Admin/HR", "Admin/HR/Contracts")
            var current = string.Empty;
            foreach (var part in parts)
            {
                current = string.IsNullOrEmpty(current) ? part.Trim() : $"{current}/{part.Trim()}";
                paths.Add(current);
            }
        }

        // Sort by depth (fewer slashes first) to ensure parent-first ordering
        return paths
            .OrderBy(p => p.Count(c => c == '/'))
            .ThenBy(p => p, StringComparer.OrdinalIgnoreCase)
            .ToList();
    }
}
