using System.IO;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using SharepointToolbox.Core.Models;
using SharepointToolbox.Infrastructure.Auth;
using SharepointToolbox.Infrastructure.Persistence;
using SharepointToolbox.Services;
using SharepointToolbox.ViewModels;

namespace SharepointToolbox.Tests.ViewModels;

[Trait("Category", "Unit")]
public class ProfileManagementViewModelRegistrationTests : IDisposable
{
    private readonly string _tempFile;
    private readonly Mock<IBrandingService> _mockBranding;
    private readonly Mock<IAppRegistrationService> _mockAppReg;
    private readonly GraphClientFactory _graphClientFactory;

    public ProfileManagementViewModelRegistrationTests()
    {
        _tempFile = Path.GetTempFileName();
        File.Delete(_tempFile);
        _mockBranding = new Mock<IBrandingService>();
        _mockAppReg = new Mock<IAppRegistrationService>();
        _graphClientFactory = new GraphClientFactory(new MsalClientFactory());
    }

    public void Dispose()
    {
        if (File.Exists(_tempFile)) File.Delete(_tempFile);
        if (File.Exists(_tempFile + ".tmp")) File.Delete(_tempFile + ".tmp");
    }

    private ProfileManagementViewModel CreateViewModel()
    {
        var profileService = new ProfileService(new ProfileRepository(_tempFile));
        return new ProfileManagementViewModel(
            profileService,
            _mockBranding.Object,
            _graphClientFactory,
            NullLogger<ProfileManagementViewModel>.Instance,
            _mockAppReg.Object);
    }

    private static TenantProfile MakeProfile(string? appId = null) => new TenantProfile
    {
        Name = "TestTenant",
        TenantUrl = "https://test.sharepoint.com",
        ClientId = "00000000-0000-0000-0000-000000000001",
        AppId = appId
    };

    [Fact]
    public void RegisterAppCommand_CanExecute_WhenProfileSelected_AndNoAppId()
    {
        var vm = CreateViewModel();
        vm.SelectedProfile = MakeProfile(appId: null);

        Assert.True(vm.RegisterAppCommand.CanExecute(null));
    }

    [Fact]
    public void RegisterAppCommand_CannotExecute_WhenNoProfile()
    {
        var vm = CreateViewModel();

        Assert.False(vm.RegisterAppCommand.CanExecute(null));
    }

    [Fact]
    public void RemoveAppCommand_CanExecute_WhenProfileHasAppId()
    {
        var vm = CreateViewModel();
        vm.SelectedProfile = MakeProfile(appId: "some-app-id");

        Assert.True(vm.RemoveAppCommand.CanExecute(null));
    }

    [Fact]
    public void RemoveAppCommand_CannotExecute_WhenNoAppId()
    {
        var vm = CreateViewModel();
        vm.SelectedProfile = MakeProfile(appId: null);

        Assert.False(vm.RemoveAppCommand.CanExecute(null));
    }

    [Fact]
    public async Task RegisterApp_ShowsFallback_WhenGraphReturnsFallbackRequired()
    {
        _mockAppReg
            .Setup(s => s.RegisterAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
            .ReturnsAsync(AppRegistrationResult.FallbackRequired());

        var vm = CreateViewModel();
        vm.SelectedProfile = MakeProfile(appId: null);

        await vm.RegisterAppCommand.ExecuteAsync(null);

        Assert.True(vm.ShowFallbackInstructions);
    }

    [Fact]
    public async Task RegisterApp_SetsAppId_OnSuccess()
    {
        _mockAppReg
            .Setup(s => s.RegisterAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
            .ReturnsAsync(AppRegistrationResult.Success("new-app-id-123"));

        var profileService = new ProfileService(new ProfileRepository(_tempFile));
        var profile = MakeProfile(appId: null);
        await profileService.AddProfileAsync(profile);

        var vm = new ProfileManagementViewModel(
            profileService,
            _mockBranding.Object,
            _graphClientFactory,
            NullLogger<ProfileManagementViewModel>.Instance,
            _mockAppReg.Object);
        vm.SelectedProfile = profile;

        await vm.RegisterAppCommand.ExecuteAsync(null);

        Assert.Equal("new-app-id-123", profile.AppId);
    }

    [Fact]
    public async Task RemoveApp_ClearsAppId()
    {
        _mockAppReg
            .Setup(s => s.RemoveAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
            .Returns(Task.CompletedTask);
        _mockAppReg
            .Setup(s => s.ClearMsalSessionAsync(It.IsAny<string>(), It.IsAny<string>()))
            .Returns(Task.CompletedTask);

        var profileService = new ProfileService(new ProfileRepository(_tempFile));
        var profile = MakeProfile(appId: "existing-app-id");
        await profileService.AddProfileAsync(profile);

        var vm = new ProfileManagementViewModel(
            profileService,
            _mockBranding.Object,
            _graphClientFactory,
            NullLogger<ProfileManagementViewModel>.Instance,
            _mockAppReg.Object);
        vm.SelectedProfile = profile;

        await vm.RemoveAppCommand.ExecuteAsync(null);

        Assert.Null(profile.AppId);
    }
}
