using System.Text.Json;

namespace YMhut.Box.Core.Startup;

public enum StartupCheckKind
{
    FastPreflight,
    MonthlyIntegrity,
    ManualIntegrity
}

public enum StartupCheckSeverity
{
    Info,
    Warning,
    Critical
}

public enum StartupCheckStatus
{
    Passed,
    Missing,
    Failed,
    Skipped
}

public sealed record StartupCheckItem(
    string Id,
    string Name,
    StartupCheckSeverity Severity,
    StartupCheckStatus Status,
    string Detail,
    string? Path = null)
{
    public bool IsIssue => Status is StartupCheckStatus.Missing or StartupCheckStatus.Failed;
}

public sealed record StartupCheckReport(
    Guid Id,
    StartupCheckKind Kind,
    DateTimeOffset StartedAt,
    DateTimeOffset CompletedAt,
    string InstallRoot,
    string ManifestIdentity,
    IReadOnlyList<StartupCheckItem> Items,
    string InstallIdentity = "",
    bool IsCurrentInstall = true,
    bool SupersededByCurrentInstall = false,
    string CheckBasis = "")
{
    public int IssueCount => Items.Count(item => item.IsIssue);

    public int CriticalIssueCount => Items.Count(item => item.IsIssue && item.Severity == StartupCheckSeverity.Critical);

    public int WarningIssueCount => Items.Count(item => item.IsIssue && item.Severity == StartupCheckSeverity.Warning);

    public int VisibleIssueCount => IsCurrentInstall
        ? Items.Count(item => item.IsIssue && !item.Id.StartsWith("repaired:", StringComparison.OrdinalIgnoreCase))
        : 0;

    public int VisibleCriticalIssueCount => IsCurrentInstall
        ? Items.Count(item => item.IsIssue &&
        item.Severity == StartupCheckSeverity.Critical &&
        !item.Id.StartsWith("repaired:", StringComparison.OrdinalIgnoreCase))
        : 0;

    public int VisibleWarningIssueCount => IsCurrentInstall
        ? Items.Count(item => item.IsIssue &&
        item.Severity == StartupCheckSeverity.Warning &&
        !item.Id.StartsWith("repaired:", StringComparison.OrdinalIgnoreCase))
        : 0;

    public bool HasVisibleIssues => VisibleIssueCount > 0;

    public bool HasCriticalIssues => CriticalIssueCount > 0;

    public static StartupCheckReport Create(
        StartupCheckKind kind,
        DateTimeOffset startedAt,
        string installRoot,
        string manifestIdentity,
        string installIdentity,
        string checkBasis,
        IEnumerable<StartupCheckItem> items)
    {
        return new StartupCheckReport(
            Guid.NewGuid(),
            kind,
            startedAt,
            DateTimeOffset.Now,
            installRoot,
            manifestIdentity,
            items.ToArray(),
            installIdentity,
            IsCurrentInstall: true,
            SupersededByCurrentInstall: false,
            checkBasis);
    }

    public string ToJson()
        => JsonSerializer.Serialize(this, StartupCheckJson.Options);
}

public sealed record StartupCheckReportSummary(
    Guid Id,
    StartupCheckKind Kind,
    DateTimeOffset StartedAt,
    DateTimeOffset CompletedAt,
    string InstallRoot,
    string ManifestIdentity,
    int ItemCount,
    int IssueCount,
    int CriticalIssueCount,
    int WarningIssueCount,
    int VisibleIssueCount,
    string InstallIdentity = "",
    bool IsCurrentInstall = true,
    bool SupersededByCurrentInstall = false,
    string CheckBasis = "")
{
    public bool HasCriticalIssues => CriticalIssueCount > 0;

    public bool HasVisibleIssues => VisibleIssueCount > 0;

    public static StartupCheckReportSummary FromReport(StartupCheckReport report)
        => new(
            report.Id,
            report.Kind,
            report.StartedAt,
            report.CompletedAt,
            report.InstallRoot,
            report.ManifestIdentity,
            report.Items.Count,
            report.IssueCount,
            report.CriticalIssueCount,
            report.WarningIssueCount,
            report.VisibleIssueCount,
            report.InstallIdentity,
            report.IsCurrentInstall,
            report.SupersededByCurrentInstall,
            report.CheckBasis);
}

public sealed record StartupInitializationSnapshot(
    DateTimeOffset StartedAt,
    DateTimeOffset CompletedAt,
    StartupCheckReport FastPreflightReport,
    int ToolCount,
    string InstallRoot)
{
    public bool HasStartupIssue => FastPreflightReport.IssueCount > 0;

    public bool HasVisibleStartupIssue => FastPreflightReport.HasVisibleIssues;

    public bool HasCriticalStartupIssue => FastPreflightReport.HasCriticalIssues;
}

public static class StartupCheckJson
{
    public static JsonSerializerOptions Options { get; } = new(JsonSerializerDefaults.Web)
    {
        WriteIndented = true
    };
}
