using System.Text.Json.Serialization;

namespace NexusShell.Models;

public sealed class NexusUpdateArtifact
{
    [JsonPropertyName("url")]
    public string Url { get; set; } = string.Empty;

    [JsonPropertyName("sha256")]
    public string Sha256 { get; set; } = string.Empty;

    [JsonPropertyName("sizeBytes")]
    public long SizeBytes { get; set; }
}

public sealed class NexusUpdateManifest
{
    [JsonPropertyName("product")]
    public string Product { get; set; } = "Ninja Nexus";

    [JsonPropertyName("channel")]
    public string Channel { get; set; } = "poc";

    [JsonPropertyName("version")]
    public string Version { get; set; } = string.Empty;

    [JsonPropertyName("build")]
    public int Build { get; set; }

    [JsonPropertyName("publishedAt")]
    public string PublishedAt { get; set; } = string.Empty;

    [JsonPropertyName("minimumSupportedBuild")]
    public int MinimumSupportedBuild { get; set; }

    [JsonPropertyName("minimumSupportedVersion")]
    public string MinimumSupportedVersion { get; set; } = string.Empty;

    [JsonPropertyName("artifact")]
    public NexusUpdateArtifact? Artifact { get; set; }

    [JsonPropertyName("packageUrl")]
    public string PackageUrl { get; set; } = string.Empty;

    [JsonPropertyName("sha256Url")]
    public string Sha256Url { get; set; } = string.Empty;

    [JsonPropertyName("sha256")]
    public string Sha256 { get; set; } = string.Empty;

    [JsonPropertyName("sizeBytes")]
    public long SizeBytes { get; set; }

    [JsonPropertyName("notes")]
    public List<string> Notes { get; set; } = [];

    [JsonPropertyName("releaseNotes")]
    public List<string> ReleaseNotes { get; set; } = [];

    [JsonPropertyName("requiresRuntime")]
    public List<string> RequiresRuntime { get; set; } = [];

    [JsonPropertyName("requiresSafePoc")]
    public bool RequiresSafePoc { get; set; } = true;

    [JsonPropertyName("mandatory")]
    public bool Mandatory { get; set; }

    [JsonPropertyName("rollbackVersion")]
    public string? RollbackVersion { get; set; }

    [JsonPropertyName("signature")]
    public string? Signature { get; set; }

    [JsonPropertyName("installerUrl")]
    public string InstallerUrl { get; set; } = string.Empty;

    [JsonPropertyName("installerSha256")]
    public string InstallerSha256 { get; set; } = string.Empty;

    [JsonPropertyName("installerSizeBytes")]
    public long InstallerSizeBytes { get; set; }

    [JsonIgnore]
    public string EffectivePackageUrl =>
        !string.IsNullOrWhiteSpace(Artifact?.Url) ? Artifact.Url : PackageUrl;

    [JsonIgnore]
    public string EffectiveSha256 =>
        !string.IsNullOrWhiteSpace(Artifact?.Sha256) ? Artifact.Sha256 : Sha256;

    [JsonIgnore]
    public long EffectiveSizeBytes =>
        Artifact?.SizeBytes > 0 ? Artifact.SizeBytes : SizeBytes;

    [JsonIgnore]
    public IReadOnlyList<string> EffectiveNotes =>
        Notes.Count > 0 ? Notes : ReleaseNotes;

    [JsonIgnore]
    public int EffectiveMinimumSupportedBuild =>
        MinimumSupportedBuild > 0 ? MinimumSupportedBuild : 1;

    public bool MeetsMinimumBuild(int currentBuild) =>
        currentBuild >= EffectiveMinimumSupportedBuild;

    public static bool IsRemoteNewer(NexusUpdateManifest remote, string currentVersion, int currentBuild)
    {
        return remote.Build > currentBuild;
    }

    public static bool IsUpdateApplicable(NexusUpdateManifest remote, string currentVersion, int currentBuild)
    {
        if (!IsRemoteNewer(remote, currentVersion, currentBuild))
        {
            return false;
        }

        return remote.MeetsMinimumBuild(currentBuild);
    }
}

public enum UpdateCheckStatus
{
    Unknown,
    Checking,
    UpToDate,
    UpdateAvailable,
    LocalBuildAhead,
    ChannelUnavailable,
    Error,
    ClientTooOld,
}

public sealed class UpdateCheckResult
{
    public UpdateCheckStatus Status { get; init; }
    public NexusUpdateManifest? RemoteManifest { get; init; }
    public string? ErrorMessage { get; init; }
    public bool IsUpdateAvailable { get; init; }
}

public enum ClientUpdateFlowState
{
    Idle,
    UpToDate,
    UpdateFound,
    Downloading,
    Validating,
    Ready,
    Preparing,
    Installing,
    Completed,
    Blocked,
    Failed,
    Cancelled,
    Stale,
}
