using System.ComponentModel;
using System.Globalization;
using SharepointToolbox.Core.Models;
using SharepointToolbox.Services;
using SharepointToolbox.Views.Dialogs;

namespace SharepointToolbox.ViewModels.Dialogs;

/// <summary>
/// Headless logic for <see cref="SitePickerDialog"/>. Loads sites via
/// <see cref="ISiteListService"/> and applies filter/sort in memory so the
/// dialog's code-behind stays a thin shim and the logic is unit-testable
/// without a WPF host.
/// </summary>
public class SitePickerDialogLogic
{
    private readonly ISiteListService _siteListService;
    private readonly TenantProfile _profile;

    public SitePickerDialogLogic(ISiteListService siteListService, TenantProfile profile)
    {
        _siteListService = siteListService;
        _profile = profile;
    }

    /// <summary>
    /// Loads all accessible sites for the tenant profile and wraps them in
    /// <see cref="SitePickerItem"/> so the dialog can bind checkboxes.
    /// </summary>
    public async Task<IReadOnlyList<SitePickerItem>> LoadAsync(
        IProgress<OperationProgress> progress,
        CancellationToken ct)
    {
        var sites = await _siteListService.GetSitesAsync(_profile, progress, ct);
        return sites
            .Select(s => new SitePickerItem(s.Url, s.Title, s.StorageUsedMb, s.StorageQuotaMb, s.Template))
            .ToList();
    }

    /// <summary>
    /// Filters items by free-text (title/url substring), storage-size range,
    /// and site kind. Empty or zero-range parameters become no-ops.
    /// </summary>
    public static IEnumerable<SitePickerItem> ApplyFilter(
        IEnumerable<SitePickerItem> items,
        string text,
        long minMb,
        long maxMb,
        string kindFilter)
    {
        var result = items;

        if (!string.IsNullOrEmpty(text))
        {
            result = result.Where(i =>
                i.Url.Contains(text, StringComparison.OrdinalIgnoreCase) ||
                i.Title.Contains(text, StringComparison.OrdinalIgnoreCase));
        }

        result = result.Where(i => i.StorageUsedMb >= minMb && i.StorageUsedMb <= maxMb);

        if (!string.IsNullOrEmpty(kindFilter) && kindFilter != "All")
            result = result.Where(i => i.Kind.ToString() == kindFilter);

        return result;
    }

    /// <summary>
    /// Stable sort by a named column and direction. Unknown column names
    /// return the input sequence unchanged.
    /// </summary>
    public static IEnumerable<SitePickerItem> ApplySort(
        IEnumerable<SitePickerItem> items,
        string column,
        ListSortDirection direction)
    {
        var asc = direction == ListSortDirection.Ascending;
        return column switch
        {
            "Title" => asc ? items.OrderBy(i => i.Title) : items.OrderByDescending(i => i.Title),
            "Url" => asc ? items.OrderBy(i => i.Url) : items.OrderByDescending(i => i.Url),
            "Kind" => asc ? items.OrderBy(i => i.KindDisplay) : items.OrderByDescending(i => i.KindDisplay),
            "StorageUsedMb" => asc
                ? items.OrderBy(i => i.StorageUsedMb)
                : items.OrderByDescending(i => i.StorageUsedMb),
            "IsSelected" => asc
                ? items.OrderBy(i => i.IsSelected)
                : items.OrderByDescending(i => i.IsSelected),
            _ => items
        };
    }

    /// <summary>
    /// Lenient long parse: whitespace-only or unparseable input yields
    /// <paramref name="fallback"/> instead of throwing.
    /// </summary>
    public static long ParseLongOrDefault(string text, long fallback)
    {
        if (string.IsNullOrWhiteSpace(text)) return fallback;
        return long.TryParse(text.Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var v)
            ? v
            : fallback;
    }
}
