using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Online.SharePoint.TenantAdministration;
using Microsoft.SharePoint.Client;
using SharepointToolbox.Core.Models;

namespace SharepointToolbox.Services;

public class SiteListService : ISiteListService
{
    private readonly SessionManager _sessionManager;

    public SiteListService(SessionManager sessionManager)
    {
        _sessionManager = sessionManager;
    }

    public async Task<IReadOnlyList<SiteInfo>> GetSitesAsync(
        TenantProfile profile,
        IProgress<OperationProgress> progress,
        CancellationToken ct)
    {
        ct.ThrowIfCancellationRequested();
        progress.Report(OperationProgress.Indeterminate("Loading sites..."));

        var adminUrl = DeriveAdminUrl(profile.TenantUrl);
        var adminProfile = new TenantProfile
        {
            Name = profile.Name,
            TenantUrl = adminUrl,
            ClientId = profile.ClientId
        };

        ClientContext adminCtx;
        try
        {
            adminCtx = await _sessionManager.GetOrCreateContextAsync(adminProfile, ct);
        }
        catch (ServerException ex) when (ex.Message.Contains("Access denied", StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException(
                "Site listing requires SharePoint administrator permissions. Connect with an admin account.", ex);
        }

        var tenant = new Tenant(adminCtx);
        var siteProps = tenant.GetSitePropertiesFromSharePoint("", true);
        adminCtx.Load(siteProps);
        await adminCtx.ExecuteQueryAsync();

        ct.ThrowIfCancellationRequested();

        return siteProps
            .Where(s => s.Status == "Active"
                && !s.Url.Contains("-my.sharepoint.com", StringComparison.OrdinalIgnoreCase))
            .Select(s => new SiteInfo(s.Url, s.Title))
            .OrderBy(s => s.Url)
            .ToList();
    }

    internal static string DeriveAdminUrl(string tenantUrl)
        => Regex.Replace(tenantUrl.TrimEnd('/'),
            @"(https://[^.]+)(\.sharepoint\.com)",
            "$1-admin$2",
            RegexOptions.IgnoreCase);
}
