using Microsoft.Extensions.Logging;
using PSLauncher.Core.Installations;
using PSLauncher.Core.Manifests;
using PSLauncher.Models;

namespace PSLauncher.Core.Updates;

public sealed class UpdateChecker : IUpdateChecker
{
    private readonly IManifestService _manifestService;
    private readonly IInstallationRegistry _registry;
    private readonly ILogger<UpdateChecker> _logger;

    public UpdateChecker(
        IManifestService manifestService,
        IInstallationRegistry registry,
        ILogger<UpdateChecker> logger)
    {
        _manifestService = manifestService;
        _registry = registry;
        _logger = logger;
    }

    public async Task<UpdateCheckResult> CheckAsync(CancellationToken ct)
    {
        try
        {
            var manifest = await _manifestService.FetchAsync(ct).ConfigureAwait(false);

            // On ignore le champ `manifest.Latest` (trop facile à oublier au serveur).
            // On prend toujours la plus haute version SemVer disponible et téléchargeable.
            var latest = manifest.Versions
                .Where(v => v.AvailableForDownload)
                .OrderByDescending(v => SemVer.Parse(v.Version))
                .FirstOrDefault();

            var installed = _registry.Scan();
            var latestInstalled = installed
                .OrderByDescending(v => SemVer.Parse(v.Version))
                .FirstOrDefault();

            var isLatestInstalled = latest is not null && latestInstalled is not null
                                    && latestInstalled.Version == latest.Version;
            var isNewer = latest is not null
                          && (latestInstalled is null
                              || SemVer.Parse(latest.Version).CompareTo(SemVer.Parse(latestInstalled.Version)) > 0);

            return new UpdateCheckResult(manifest, latest, latestInstalled, isLatestInstalled, isNewer, null);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Update check failed");
            return new UpdateCheckResult(null, null, null, false, false, ex.Message);
        }
    }
}
