using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.SharePoint.Client;
using Moq;
using SharepointToolbox.Core.Messages;
using SharepointToolbox.Core.Models;
using SharepointToolbox.Services;
using SharepointToolbox.ViewModels;
using SharepointToolbox.ViewModels.Tabs;

namespace SharepointToolbox.Tests.ViewModels;

/// <summary>
/// Unit tests for PermissionsViewModel.
/// PERM-02: multi-site scan loop invokes ScanSiteAsync once per URL.
/// </summary>
public class PermissionsViewModelTests
{
    [Fact]
    public async Task StartScanAsync_WithMultipleSiteUrls_CallsServiceOncePerUrl()
    {
        // Arrange
        var mockPermissionsService = new Mock<IPermissionsService>();
        mockPermissionsService
            .Setup(s => s.ScanSiteAsync(
                It.IsAny<ClientContext>(),
                It.IsAny<ScanOptions>(),
                It.IsAny<IProgress<OperationProgress>>(),
                It.IsAny<CancellationToken>()))
            .ReturnsAsync(new List<PermissionEntry>());

        var mockSiteListService = new Mock<ISiteListService>();

        var mockSessionManager = new Mock<ISessionManager>();
        mockSessionManager
            .Setup(s => s.GetOrCreateContextAsync(It.IsAny<TenantProfile>(), It.IsAny<CancellationToken>()))
            .ReturnsAsync((ClientContext)null!);

        var vm = new PermissionsViewModel(
            mockPermissionsService.Object,
            mockSiteListService.Object,
            mockSessionManager.Object,
            new NullLogger<FeatureViewModelBase>());

        // Set up two site URLs via global site selection
        WeakReferenceMessenger.Default.Send(new GlobalSitesChangedMessage(
            new List<SiteInfo>
            {
                new("https://tenant1.sharepoint.com/sites/alpha", "Alpha"),
                new("https://tenant1.sharepoint.com/sites/beta", "Beta")
            }.AsReadOnly()));
        vm.SetCurrentProfile(new TenantProfile
        {
            Name = "Test",
            TenantUrl = "https://tenant1.sharepoint.com",
            ClientId = "client-id"
        });

        // Act
        await vm.TestRunOperationAsync(CancellationToken.None, new Progress<OperationProgress>());

        // Assert: ScanSiteAsync called exactly twice (once per URL)
        mockPermissionsService.Verify(
            s => s.ScanSiteAsync(
                It.IsAny<ClientContext>(),
                It.IsAny<ScanOptions>(),
                It.IsAny<IProgress<OperationProgress>>(),
                It.IsAny<CancellationToken>()),
            Times.Exactly(2));
    }

    /// <summary>
    /// Creates a PermissionsViewModel with mocked services where ScanSiteAsync returns the given results.
    /// </summary>
    private static PermissionsViewModel CreateViewModelWithResults(IReadOnlyList<PermissionEntry> results)
    {
        var mockPermissionsService = new Mock<IPermissionsService>();
        mockPermissionsService
            .Setup(s => s.ScanSiteAsync(
                It.IsAny<ClientContext>(),
                It.IsAny<ScanOptions>(),
                It.IsAny<IProgress<OperationProgress>>(),
                It.IsAny<CancellationToken>()))
            .ReturnsAsync(results.ToList());

        var mockSiteListService = new Mock<ISiteListService>();

        var mockSessionManager = new Mock<ISessionManager>();
        mockSessionManager
            .Setup(s => s.GetOrCreateContextAsync(It.IsAny<TenantProfile>(), It.IsAny<CancellationToken>()))
            .ReturnsAsync((ClientContext)null!);

        var vm = new PermissionsViewModel(
            mockPermissionsService.Object,
            mockSiteListService.Object,
            mockSessionManager.Object,
            new NullLogger<FeatureViewModelBase>());

        return vm;
    }

    [Fact]
    public void IsSimplifiedMode_Default_IsFalse()
    {
        WeakReferenceMessenger.Default.Reset();
        var vm = CreateViewModelWithResults(Array.Empty<PermissionEntry>());
        Assert.False(vm.IsSimplifiedMode);
    }

    [Fact]
    public async Task IsSimplifiedMode_WhenToggled_RebuildsSimplifiedResults()
    {
        WeakReferenceMessenger.Default.Reset();
        var entries = new List<PermissionEntry>
        {
            new("Site", "Test", "https://test.sharepoint.com", true, "User1", "user1@test.com", "Full Control", "Direct Permissions", "User"),
            new("List", "Docs", "https://test.sharepoint.com/docs", false, "User2", "user2@test.com", "Read", "Direct Permissions", "User"),
        };

        var vm = CreateViewModelWithResults(entries);

        // Simulate scan completing
        WeakReferenceMessenger.Default.Send(new GlobalSitesChangedMessage(
            new List<SiteInfo> { new("https://test.sharepoint.com", "Test") }.AsReadOnly()));
        vm.SetCurrentProfile(new TenantProfile { Name = "Test", TenantUrl = "https://test.sharepoint.com", ClientId = "cid" });
        await vm.TestRunOperationAsync(CancellationToken.None, new Progress<OperationProgress>());

        // Before toggle: simplified results empty
        Assert.Empty(vm.SimplifiedResults);

        // Toggle on
        vm.IsSimplifiedMode = true;

        // After toggle: simplified results populated
        Assert.Equal(2, vm.SimplifiedResults.Count);
        Assert.Equal(4, vm.Summaries.Count);
    }

    [Fact]
    public async Task IsDetailView_Toggle_DoesNotChangeCounts()
    {
        WeakReferenceMessenger.Default.Reset();
        var entries = new List<PermissionEntry>
        {
            new("Site", "Test", "https://test.sharepoint.com", true, "User1", "user1@test.com", "Contribute", "Direct Permissions", "User"),
        };

        var vm = CreateViewModelWithResults(entries);
        WeakReferenceMessenger.Default.Send(new GlobalSitesChangedMessage(
            new List<SiteInfo> { new("https://test.sharepoint.com", "Test") }.AsReadOnly()));
        vm.SetCurrentProfile(new TenantProfile { Name = "Test", TenantUrl = "https://test.sharepoint.com", ClientId = "cid" });
        await vm.TestRunOperationAsync(CancellationToken.None, new Progress<OperationProgress>());

        vm.IsSimplifiedMode = true;
        var countBefore = vm.SimplifiedResults.Count;

        vm.IsDetailView = false;
        Assert.Equal(countBefore, vm.SimplifiedResults.Count);  // No re-computation

        vm.IsDetailView = true;
        Assert.Equal(countBefore, vm.SimplifiedResults.Count);  // Still the same
    }

    [Fact]
    public async Task Summaries_ContainsCorrectRiskBreakdown()
    {
        WeakReferenceMessenger.Default.Reset();
        var entries = new List<PermissionEntry>
        {
            new("Site", "S1", "https://s1", true, "Admin", "admin@t.com", "Full Control", "Direct", "User"),
            new("Site", "S2", "https://s2", true, "Editor", "ed@t.com", "Contribute", "Direct", "User"),
            new("List", "L1", "https://l1", false, "Reader", "read@t.com", "Read", "Direct", "User"),
        };

        var vm = CreateViewModelWithResults(entries);
        WeakReferenceMessenger.Default.Send(new GlobalSitesChangedMessage(
            new List<SiteInfo> { new("https://s1", "S1") }.AsReadOnly()));
        vm.SetCurrentProfile(new TenantProfile { Name = "Test", TenantUrl = "https://s1", ClientId = "cid" });
        await vm.TestRunOperationAsync(CancellationToken.None, new Progress<OperationProgress>());

        vm.IsSimplifiedMode = true;

        var high = vm.Summaries.Single(s => s.RiskLevel == RiskLevel.High);
        var medium = vm.Summaries.Single(s => s.RiskLevel == RiskLevel.Medium);
        var low = vm.Summaries.Single(s => s.RiskLevel == RiskLevel.Low);

        Assert.Equal(1, high.Count);
        Assert.Equal(1, medium.Count);
        Assert.Equal(1, low.Count);
    }
}
