using System.IO;
using NexusShell.Models;
using NexusShell.Services;
using NexusShell.Services.Deployment;
using Xunit;

namespace NexusShell.Tests;

public sealed class NexusDeploymentEngineTests : IDisposable
{
    private readonly string _root;
    private readonly NexusPackageRepository _repository;
    private readonly NexusPackageRegistry _registry;
    private readonly NexusDeploymentService _deployment;

    public NexusDeploymentEngineTests()
    {
        _root = Path.Combine(Path.GetTempPath(), "nxp-deploy-test-" + Guid.NewGuid().ToString("N"));
        _repository = new NexusPackageRepository(rootDir: _root);
        _repository.Load();

        var reader = new NexusPackageReader();
        var validator = new NexusPackageValidator();
        var installer = new NexusPackageInstaller(_repository, reader, validator);
        var rollback = new NexusRollbackService(_repository);
        var updater = new NexusPackageUpdater(_repository, installer, rollback);
        var queue = new NexusInstallQueue();
        var installedApps = new NexusInstalledAppsService();

        _registry = new NexusPackageRegistry(_repository);
        _deployment = new NexusDeploymentService(
            queue, _registry, installer, updater, rollback, _repository, installedApps);
    }

    [Fact]
    public async Task Install_extracts_package_to_installed_directory()
    {
        var packageId = "nexus-media";
        var result = await _deployment.InstallAsync(packageId);

        Assert.True(result.Success, result.Message);
        Assert.True(Directory.Exists(Path.Combine(_repository.InstalledDirectory, packageId)));
        Assert.True(File.Exists(Path.Combine(_repository.InstalledDirectory, packageId, "manifest.json")));

        var record = _repository.GetInstalledRecord(packageId);
        Assert.NotNull(record);
        Assert.Equal("0.8.5", record!.InstalledVersion);
    }

    [Fact]
    public async Task Update_replaces_installed_version_when_catalog_is_newer()
    {
        var packageId = "nexus-files";
        var update = await _deployment.UpdateAsync(packageId);

        Assert.True(update.Success, update.Message);
        var record = _repository.GetInstalledRecord(packageId);
        Assert.NotNull(record);
        Assert.Equal("1.2.0", record!.InstalledVersion);
    }

    [Fact]
    public async Task Remove_deletes_installed_folder_and_metadata()
    {
        var packageId = "nexus-browser";
        var remove = await _deployment.RemoveAsync(packageId);

        Assert.True(remove.Success, remove.Message);
        Assert.False(Directory.Exists(Path.Combine(_repository.InstalledDirectory, packageId)));
        Assert.Null(_repository.GetInstalledRecord(packageId));
    }

    public void Dispose()
    {
        if (Directory.Exists(_root))
        {
            Directory.Delete(_root, recursive: true);
        }
    }
}
