using System.Globalization;
using System.Text.Json;
using YMhut.Box.Core.App;
using YMhut.Box.Core.Logging;

namespace YMhut.Box.Core.Startup;

public interface IInstallIntegrityCheckService
{
    Task<StartupCheckReport> RunFastPreflightAsync(CancellationToken cancellationToken = default);

    Task<StartupCheckReport> RunMonthlyIntegrityCheckAsync(CancellationToken cancellationToken = default);

    Task<StartupCheckReport> RunManualIntegrityCheckAsync(CancellationToken cancellationToken = default);

    Task<StartupCheckReport?> GetLatestReportAsync(CancellationToken cancellationToken = default);

    Task<StartupCheckReport?> GetLatestReportAsync(StartupCheckKind kind, CancellationToken cancellationToken = default);

    Task<StartupCheckReport?> GetLatestCurrentReportAsync(CancellationToken cancellationToken = default);

    Task<StartupCheckReport?> GetLatestCurrentReportAsync(StartupCheckKind kind, CancellationToken cancellationToken = default);

    Task<StartupCheckReport?> GetReportAsync(Guid id, CancellationToken cancellationToken = default);

    Task<IReadOnlyList<StartupCheckReportSummary>> GetHistorySummariesAsync(int take = 30, CancellationToken cancellationToken = default);

    Task<IReadOnlyList<StartupCheckReport>> GetHistoryAsync(int take = 30, CancellationToken cancellationToken = default);

    Task<IReadOnlyList<StartupCheckReportSummary>> GetCurrentHistoryAsync(int take = 30, CancellationToken cancellationToken = default);

    Task<StartupCheckItem?> RecheckItemAsync(Guid reportId, string itemId, CancellationToken cancellationToken = default);
}

public sealed class InstallIntegrityCheckService(
    AppPaths paths,
    IStartupCheckStore store,
    ILogService? logService = null,
    string? baseDirectory = null,
    Func<DateTimeOffset>? clock = null) : IInstallIntegrityCheckService
{
    private static readonly TimeSpan MonthlyInterval = TimeSpan.FromDays(30);
    private static readonly string[] SupportedCultures = ["zh-CN", "en-US"];
    private static readonly string[] LaunchableExtensions = [".exe", ".bat", ".cmd", ".lnk", ".msc", ".ps1", ".vbs"];
    private static readonly string[] CriticalRelativeFiles =
    [
        "YMhutBox.exe",
        "YMhutBox.dll",
        "resources.pri"
    ];

    private readonly string? _baseDirectory = baseDirectory;
    private readonly Func<DateTimeOffset> _clock = clock ?? (() => DateTimeOffset.Now);

    public Task<StartupCheckReport> RunFastPreflightAsync(CancellationToken cancellationToken = default)
        => RunIntegrityCoreAsync(StartupCheckKind.FastPreflight, includeFullPayloadChecks: false, cancellationToken);

    public async Task<StartupCheckReport> RunMonthlyIntegrityCheckAsync(CancellationToken cancellationToken = default)
    {
        var context = ResolveCurrentContext();
        var latest = await GetLatestCurrentReportAsync(StartupCheckKind.MonthlyIntegrity, cancellationToken).ConfigureAwait(false);
        if (latest is not null &&
            latest.CompletedAt + MonthlyInterval > _clock() &&
            string.Equals(latest.InstallIdentity, context.InstallIdentity, StringComparison.OrdinalIgnoreCase))
        {
            return latest;
        }

        return await RunIntegrityCoreAsync(StartupCheckKind.MonthlyIntegrity, includeFullPayloadChecks: true, cancellationToken).ConfigureAwait(false);
    }

    public Task<StartupCheckReport> RunManualIntegrityCheckAsync(CancellationToken cancellationToken = default)
        => RunIntegrityCoreAsync(StartupCheckKind.ManualIntegrity, includeFullPayloadChecks: true, cancellationToken);

    public Task<StartupCheckReport?> GetLatestReportAsync(CancellationToken cancellationToken = default)
        => GetLatestReportCoreAsync(null, cancellationToken);

    public Task<StartupCheckReport?> GetLatestReportAsync(StartupCheckKind kind, CancellationToken cancellationToken = default)
        => GetLatestReportCoreAsync(kind, cancellationToken);

    public Task<StartupCheckReport?> GetLatestCurrentReportAsync(CancellationToken cancellationToken = default)
        => GetLatestCurrentReportCoreAsync(null, cancellationToken);

    public Task<StartupCheckReport?> GetLatestCurrentReportAsync(StartupCheckKind kind, CancellationToken cancellationToken = default)
        => GetLatestCurrentReportCoreAsync(kind, cancellationToken);

    public async Task<StartupCheckReport?> GetReportAsync(Guid id, CancellationToken cancellationToken = default)
    {
        var report = await store.GetReportAsync(id, cancellationToken).ConfigureAwait(false);
        return report is null ? null : MarkCurrentInstall(report, ResolveCurrentContext());
    }

    public async Task<IReadOnlyList<StartupCheckReportSummary>> GetHistorySummariesAsync(int take = 30, CancellationToken cancellationToken = default)
    {
        var context = ResolveCurrentContext();
        var summaries = await store.GetHistorySummariesAsync(take, cancellationToken).ConfigureAwait(false);
        return summaries.Select(summary => MarkCurrentInstall(summary, context)).ToArray();
    }

    public async Task<IReadOnlyList<StartupCheckReport>> GetHistoryAsync(int take = 30, CancellationToken cancellationToken = default)
    {
        var context = ResolveCurrentContext();
        var reports = await store.GetHistoryAsync(take, cancellationToken).ConfigureAwait(false);
        return reports.Select(report => MarkCurrentInstall(report, context)).ToArray();
    }

    public async Task<IReadOnlyList<StartupCheckReportSummary>> GetCurrentHistoryAsync(int take = 30, CancellationToken cancellationToken = default)
    {
        var context = ResolveCurrentContext();
        var history = await store.GetHistoryAsync(Math.Max(take, 200), cancellationToken).ConfigureAwait(false);
        return history
            .Select(report => MarkCurrentInstall(report, context))
            .Where(report => report.IsCurrentInstall)
            .Take(Math.Clamp(take, 1, 200))
            .Select(StartupCheckReportSummary.FromReport)
            .ToArray();
    }

    public async Task<StartupCheckItem?> RecheckItemAsync(Guid reportId, string itemId, CancellationToken cancellationToken = default)
    {
        var report = await GetReportAsync(reportId, cancellationToken).ConfigureAwait(false);
        var item = report?.Items.FirstOrDefault(candidate => string.Equals(candidate.Id, itemId, StringComparison.OrdinalIgnoreCase));
        return item is null ? null : RecheckItem(item, ResolveCurrentContext());
    }

    private async Task<StartupCheckReport> RunIntegrityCoreAsync(
        StartupCheckKind kind,
        bool includeFullPayloadChecks,
        CancellationToken cancellationToken)
    {
        var startedAt = _clock();
        var context = ResolveCurrentContext();
        var installRoot = context.InstallRoot;
        var manifest = TryReadManifest(installRoot, out var manifestPath, out var manifestError);
        var rootCultureFallback = HasAnySupportedRootCultureResources(installRoot);
        var items = new List<StartupCheckItem>();

        CheckWritableDirectory(items, "user-root", "用户数据目录", paths.Root, StartupCheckSeverity.Critical);
        CheckWritableDirectory(items, "logs", "日志目录", paths.Logs, StartupCheckSeverity.Critical);
        CheckWritableDirectory(items, "data", "数据目录", paths.Data, StartupCheckSeverity.Critical);
        CheckWritableDirectory(items, "sqlite-parent", "主 SQLite 存储目录", Path.GetDirectoryName(AppDatabasePaths.ResolveMainDatabasePath(paths)) ?? paths.Logs, StartupCheckSeverity.Critical);
        AddDirectoryCheck(items, "install-root", "安装目录", installRoot, StartupCheckSeverity.Critical);
        if (manifest is null)
        {
            items.Add(Skipped(
                "manifest",
                "安装清单",
                manifestError ?? "当前安装目录未包含安装清单；按当前目录实际文件执行降噪检查。",
                manifestPath));
        }
        else
        {
            AddFileCheck(items, "manifest", "安装清单", manifestPath, StartupCheckSeverity.Info);
        }

        foreach (var relativePath in CriticalRelativeFiles)
        {
            AddRelativeFileCheck(items, installRoot, relativePath, CriticalFileSeverity(relativePath, manifest, rootCultureFallback));
        }

        AddPureLanguageChecks(items, installRoot, strictPureLang: manifest is not null, allowRootCultureFallback: rootCultureFallback);
        AddAppDataPayloadChecks(items);
        AddToolsChecks(items, installRoot, includeFullPayloadChecks ? manifest : null);
        AddMetadataChecks(items, installRoot);

        if (includeFullPayloadChecks)
        {
            if (manifest is not null)
            {
                AddManifestFileChecks(items, installRoot, manifest);
            }
        }

        var report = StartupCheckReport.Create(
            kind,
            startedAt,
            installRoot,
            context.ManifestIdentity,
            context.InstallIdentity,
            context.CheckBasis,
            items);
        await SaveAndLogAsync(report, cancellationToken).ConfigureAwait(false);
        return report;
    }

    private static InstallManifest? TryReadManifest(string installRoot, out string manifestPath, out string? error)
    {
        manifestPath = Path.Combine(installRoot, InstallManifest.RelativePath.Replace('/', Path.DirectorySeparatorChar));
        error = null;
        try
        {
            if (!File.Exists(manifestPath))
            {
                error = "未找到安装清单。开发构建可继续使用，正式安装包应包含该文件。";
                return null;
            }

            return InstallManifest.Parse(File.ReadAllText(manifestPath));
        }
        catch (Exception exception)
        {
            error = $"安装清单读取失败：{Sanitize(exception.Message)}";
            return null;
        }
    }

    private static void CheckWritableDirectory(
        ICollection<StartupCheckItem> items,
        string id,
        string name,
        string directory,
        StartupCheckSeverity severity)
    {
        try
        {
            Directory.CreateDirectory(directory);
            var probe = Path.Combine(directory, $".ymhut-probe-{Guid.NewGuid():N}.tmp");
            File.WriteAllText(probe, "ok");
            File.Delete(probe);
            items.Add(Passed(id, name, $"可写：{directory}", directory));
        }
        catch (Exception exception)
        {
            items.Add(Failed(id, name, severity, $"目录不可写：{Sanitize(exception.Message)}", directory));
        }
    }

    private static void AddDirectoryCheck(
        ICollection<StartupCheckItem> items,
        string id,
        string name,
        string directory,
        StartupCheckSeverity severity)
    {
        items.Add(Directory.Exists(directory)
            ? Passed(id, name, $"目录存在：{directory}", directory)
            : Missing(id, name, severity, "目录缺失", directory));
    }

    private static void AddFileCheck(
        ICollection<StartupCheckItem> items,
        string id,
        string name,
        string path,
        StartupCheckSeverity severity,
        string? missingDetail = null)
    {
        items.Add(File.Exists(path)
            ? Passed(id, name, $"文件存在：{path}", path)
            : Missing(id, name, severity, missingDetail ?? "文件缺失", path));
    }

    private static void AddRelativeFileCheck(
        ICollection<StartupCheckItem> items,
        string installRoot,
        string relativePath,
        StartupCheckSeverity severity)
    {
        var normalized = Normalize(relativePath);
        var path = Path.Combine(installRoot, relativePath.Replace('/', Path.DirectorySeparatorChar));
        if (normalized.Equals("resources.pri", StringComparison.OrdinalIgnoreCase) && !File.Exists(path))
        {
            var appPri = Path.Combine(installRoot, "YMhutBox.pri");
            if (File.Exists(appPri))
            {
                items.Add(Passed(
                    $"file:{normalized}",
                    "resources.pri / YMhutBox.pri",
                    "检测到当前 WinUI 开发/运行输出使用 YMhutBox.pri，资源索引可用。",
                    appPri));
                return;
            }
        }

        AddFileCheck(
            items,
            $"file:{normalized}",
            relativePath,
            path,
            severity);
    }

    private static StartupCheckSeverity CriticalFileSeverity(string relativePath, InstallManifest? manifest, bool allowRootCultureFallback)
    {
        if (manifest is null &&
            allowRootCultureFallback &&
            string.Equals(Normalize(relativePath), "resources.pri", StringComparison.OrdinalIgnoreCase))
        {
            return StartupCheckSeverity.Warning;
        }

        return StartupCheckSeverity.Critical;
    }

    private static void AddPureLanguageChecks(
        ICollection<StartupCheckItem> items,
        string installRoot,
        bool strictPureLang,
        bool allowRootCultureFallback)
    {
        var resourcesLang = Path.Combine(installRoot, "resources", "lang");
        if (Directory.Exists(resourcesLang))
        {
            items.Add(Failed(
                "lang:legacy-resources",
                "旧语言压缩目录",
                StartupCheckSeverity.Critical,
                "检测到 resources\\lang。正式发布布局应只使用 lang\\zh-CN 和 lang\\en-US。",
                resourcesLang));
        }
        else
        {
            items.Add(Passed("lang:legacy-resources", "旧语言压缩目录", "未检测到 resources\\lang。", resourcesLang));
        }

        foreach (var culture in SupportedCultures)
        {
            var cultureRoot = Path.Combine(installRoot, "lang", culture);
            var hasRootCultureFallback = allowRootCultureFallback && HasRootCultureResources(installRoot, culture);
            var missingSeverity = strictPureLang || !hasRootCultureFallback
                ? StartupCheckSeverity.Critical
                : StartupCheckSeverity.Warning;
            if (!Directory.Exists(cultureRoot))
            {
                items.Add(hasRootCultureFallback
                    ? Passed(
                        $"lang:{culture}",
                        $"语言资源 {culture}",
                        "检测到当前开发/运行输出的根目录语言资源，语言资源可用。",
                        Path.Combine(installRoot, culture))
                    : Missing(
                        $"lang:{culture}",
                        $"语言资源 {culture}",
                        missingSeverity,
                        "语言目录缺失",
                        cultureRoot));
                continue;
            }

            var hasSatellite = Directory.EnumerateFiles(cultureRoot, "*.mui", SearchOption.AllDirectories).Any() ||
                Directory.EnumerateFiles(cultureRoot, "*.resources.dll", SearchOption.AllDirectories).Any();
            items.Add(hasSatellite
                ? Passed($"lang:{culture}", $"语言资源 {culture}", "语言资源已展开。", cultureRoot)
                : hasRootCultureFallback
                    ? Passed(
                        $"lang:{culture}",
                        $"语言资源 {culture}",
                        "lang 目录未展开 MUI 或 resources.dll，但根目录语言资源可用。",
                        Path.Combine(installRoot, culture))
                    : Missing(
                        $"lang:{culture}",
                        $"语言资源 {culture}",
                        missingSeverity,
                        "语言资源目录中没有 MUI 或 resources.dll。",
                        cultureRoot));
        }

        var rootCultures = (Directory.Exists(installRoot)
            ? Directory.EnumerateDirectories(installRoot)
                .Select(Path.GetFileName)
                .Where(name => !string.IsNullOrWhiteSpace(name) && LooksLikeCultureName(name!))
                .OrderBy(name => name, StringComparer.OrdinalIgnoreCase)
                .ToArray()
            : Array.Empty<string>());
        if (rootCultures.Length > 0)
        {
            items.Add(Skipped(
                "lang:root-culture-summary",
                "根目录语言资源",
                $"检测到 {rootCultures.Length} 个运行时/框架语言资源目录，已识别为当前安装目录的正常卫星资源，不计入问题。",
                installRoot));
        }
    }

    private static bool HasAnySupportedRootCultureResources(string installRoot)
        => SupportedCultures.Any(culture => HasRootCultureResources(installRoot, culture));

    private static bool HasRootCultureResources(string installRoot, string culture)
    {
        try
        {
            var cultureRoot = Path.Combine(installRoot, culture);
            if (!Directory.Exists(cultureRoot))
            {
                return false;
            }

            return Directory.EnumerateFiles(cultureRoot, "*.mui", SearchOption.AllDirectories).Any() ||
                Directory.EnumerateFiles(cultureRoot, "*.resources.dll", SearchOption.AllDirectories).Any();
        }
        catch
        {
            return false;
        }
    }

    private void AddAppDataPayloadChecks(ICollection<StartupCheckItem> items)
    {
        var removed = paths.CleanupUserPayloadDirectories()
            .ToHashSet(StringComparer.OrdinalIgnoreCase);

        foreach (var relative in AppPaths.UserPayloadDirectoryNames.Distinct(StringComparer.OrdinalIgnoreCase))
        {
            var path = Path.Combine(paths.Root, relative);
            if (Directory.Exists(path))
            {
                items.Add(new StartupCheckItem(
                    $"userdata:{relative.ToLowerInvariant()}",
                    $"User data {relative}",
                    StartupCheckSeverity.Info,
                    StartupCheckStatus.Skipped,
                    "Legacy user payload remains, but current install health is based only on the active install directory.",
                    path));
                continue;
            }

            items.Add(Passed(
                $"userdata:{relative.ToLowerInvariant()}",
                $"User data {relative}",
                removed.Contains(path)
                    ? "Removed a legacy payload copy from the user data folder."
                    : "No legacy payload copy found in the user data folder.",
                path));
        }
    }

    private static void AddManifestFileChecks(ICollection<StartupCheckItem> items, string installRoot, InstallManifest manifest)
    {
        foreach (var relativePath in manifest.RequiredFiles.Distinct(StringComparer.OrdinalIgnoreCase))
        {
            AddRelativeFileCheck(items, installRoot, relativePath, StartupCheckSeverity.Critical);
        }

        foreach (var relativePath in manifest.Files
            .Where(ShouldVerifyPayloadFile)
            .Distinct(StringComparer.OrdinalIgnoreCase))
        {
            var severity = relativePath.StartsWith("Tools/", StringComparison.OrdinalIgnoreCase) ||
                relativePath.StartsWith("Metadata/", StringComparison.OrdinalIgnoreCase)
                    ? StartupCheckSeverity.Warning
                    : StartupCheckSeverity.Critical;
            AddRelativeFileCheck(items, installRoot, relativePath, severity);
        }
    }

    private static bool ShouldVerifyPayloadFile(string relativePath)
    {
        var normalized = Normalize(relativePath);
        return normalized.StartsWith("lang/", StringComparison.OrdinalIgnoreCase) ||
            normalized.StartsWith("Tools/", StringComparison.OrdinalIgnoreCase) ||
            normalized.StartsWith("Metadata/", StringComparison.OrdinalIgnoreCase) ||
            normalized.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) ||
            normalized.EndsWith(".exe", StringComparison.OrdinalIgnoreCase) ||
            normalized.EndsWith(".mui", StringComparison.OrdinalIgnoreCase) ||
            normalized.Equals("resources.pri", StringComparison.OrdinalIgnoreCase);
    }

    private static void AddToolsChecks(ICollection<StartupCheckItem> items, string installRoot, InstallManifest? manifest)
    {
        var toolsRoot = Path.Combine(installRoot, "Tools");
        if (!Directory.Exists(toolsRoot))
        {
            items.Add(Missing("tools:root", "随包工具目录", StartupCheckSeverity.Warning, "Tools 目录缺失，外部工具将不可用。", toolsRoot));
            return;
        }

        var launchables = Directory.EnumerateFiles(toolsRoot, "*", SearchOption.AllDirectories)
            .Where(path => LaunchableExtensions.Contains(Path.GetExtension(path), StringComparer.OrdinalIgnoreCase))
            .Take(5000)
            .ToArray();
        items.Add(launchables.Length > 0
            ? Passed("tools:launchables", "外部工具启动项", $"检测到 {launchables.Length} 个启动项。", toolsRoot)
            : Missing("tools:launchables", "外部工具启动项", StartupCheckSeverity.Warning, "Tools 目录中没有可启动文件。", toolsRoot));

        if (manifest is null)
        {
            return;
        }

        foreach (var relativePath in manifest.Files
            .Where(path => Normalize(path).StartsWith("Tools/", StringComparison.OrdinalIgnoreCase) &&
                LaunchableExtensions.Contains(Path.GetExtension(path), StringComparer.OrdinalIgnoreCase))
            .Distinct(StringComparer.OrdinalIgnoreCase))
        {
            AddRelativeFileCheck(items, installRoot, relativePath, StartupCheckSeverity.Warning);
        }
    }

    private static void AddMetadataChecks(ICollection<StartupCheckItem> items, string installRoot)
    {
        var metadataRoot = Path.Combine(installRoot, "Metadata");
        if (!Directory.Exists(metadataRoot))
        {
            items.Add(Missing("metadata:root", "工具元数据目录", StartupCheckSeverity.Warning, "Metadata 目录缺失，外部工具说明会降级。", metadataRoot));
            return;
        }

        var jsonFiles = Directory.EnumerateFiles(metadataRoot, "*.json", SearchOption.AllDirectories).Take(500).ToArray();
        if (jsonFiles.Length == 0)
        {
            items.Add(Missing("metadata:json", "工具元数据 JSON", StartupCheckSeverity.Warning, "Metadata 目录中没有 JSON 元数据。", metadataRoot));
            return;
        }

        var invalid = new List<string>();
        foreach (var file in jsonFiles)
        {
            try
            {
                using var stream = File.OpenRead(file);
                using var _ = JsonDocument.Parse(stream);
            }
            catch
            {
                invalid.Add(file);
                if (invalid.Count >= 5)
                {
                    break;
                }
            }
        }

        items.Add(invalid.Count == 0
            ? Passed("metadata:json", "工具元数据 JSON", $"检测到 {jsonFiles.Length} 个可解析 JSON。", metadataRoot)
            : Failed("metadata:json", "工具元数据 JSON", StartupCheckSeverity.Warning, $"发现无法解析的 JSON：{string.Join("; ", invalid)}", metadataRoot));
    }

    private async Task SaveAndLogAsync(StartupCheckReport report, CancellationToken cancellationToken)
    {
        await store.SaveAsync(report, cancellationToken).ConfigureAwait(false);
        if (logService is not null)
        {
            var level = report.HasCriticalIssues ? "Error" : report.HasVisibleIssues ? "Warning" : "Information";
            await logService.WriteAsync(
                level,
                "startup-check",
                "启动自检完成",
                $"kind={report.Kind}; issues={report.IssueCount}; visible={report.VisibleIssueCount}; critical={report.CriticalIssueCount}; root={report.InstallRoot}",
                cancellationToken).ConfigureAwait(false);
        }
    }

    private async Task<StartupCheckReport?> GetLatestReportCoreAsync(StartupCheckKind? kind, CancellationToken cancellationToken)
    {
        var report = kind is null
            ? await store.GetLatestReportAsync(cancellationToken).ConfigureAwait(false)
            : await store.GetLatestReportAsync(kind.Value, cancellationToken).ConfigureAwait(false);
        return report is null ? null : MarkCurrentInstall(report, ResolveCurrentContext());
    }

    private async Task<StartupCheckReport?> GetLatestCurrentReportCoreAsync(StartupCheckKind? kind, CancellationToken cancellationToken)
    {
        var context = ResolveCurrentContext();
        var history = await store.GetHistoryAsync(200, cancellationToken).ConfigureAwait(false);
        return history
            .Select(report => MarkCurrentInstall(report, context))
            .Where(report => report.IsCurrentInstall && (kind is null || report.Kind == kind.Value))
            .OrderByDescending(report => report.CompletedAt)
            .FirstOrDefault();
    }

    private InstallRootContext ResolveCurrentContext()
        => InstallLayoutPaths.ResolveInstallRootContext(_baseDirectory);

    private static StartupCheckReport MarkCurrentInstall(StartupCheckReport report, InstallRootContext context)
    {
        var installIdentity = string.IsNullOrWhiteSpace(report.InstallIdentity)
            ? InstallRootContext.BuildInstallIdentity(report.InstallRoot, report.ManifestIdentity)
            : report.InstallIdentity;
        var isCurrent = string.Equals(installIdentity, context.InstallIdentity, StringComparison.OrdinalIgnoreCase);
        var items = isCurrent ? NormalizeCurrentInstallLegacyItems(report.Items, context) : report.Items;
        return report with
        {
            Items = items,
            InstallIdentity = installIdentity,
            IsCurrentInstall = isCurrent,
            SupersededByCurrentInstall = !isCurrent,
            CheckBasis = string.IsNullOrWhiteSpace(report.CheckBasis)
                ? $"installRoot={report.InstallRoot}; manifest={report.ManifestIdentity}"
                : report.CheckBasis
        };
    }

    private static IReadOnlyList<StartupCheckItem> NormalizeCurrentInstallLegacyItems(
        IReadOnlyList<StartupCheckItem> items,
        InstallRootContext context)
    {
        if (items.Count == 0)
        {
            return items;
        }

        return items.Select(item => NormalizeCurrentInstallLegacyItem(item, context)).ToArray();
    }

    private static StartupCheckItem NormalizeCurrentInstallLegacyItem(StartupCheckItem item, InstallRootContext context)
    {
        if (!item.IsIssue)
        {
            return item;
        }

        if (item.Id.StartsWith("lang:root:", StringComparison.OrdinalIgnoreCase))
        {
            var culture = item.Id["lang:root:".Length..];
            var culturePath = Path.Combine(context.InstallRoot, culture);
            if (HasRootCultureResources(context.InstallRoot, culture))
            {
                return item with
                {
                    Severity = StartupCheckSeverity.Info,
                    Status = StartupCheckStatus.Skipped,
                    Detail = "旧版报告将根目录运行时语言资源记录为异常；当前版本已识别为正常卫星资源，旧记录仅供参考。",
                    Path = culturePath
                };
            }
        }

        if (item.Id is "lang:zh-CN" or "lang:en-US")
        {
            var culture = item.Id["lang:".Length..];
            if (HasRootCultureResources(context.InstallRoot, culture))
            {
                return item with
                {
                    Severity = StartupCheckSeverity.Info,
                    Status = StartupCheckStatus.Passed,
                    Detail = "检测到当前开发/运行输出的根目录语言资源，语言资源可用；旧记录仅供参考。",
                    Path = Path.Combine(context.InstallRoot, culture)
                };
            }
        }

        if (item.Id.Equals("file:resources.pri", StringComparison.OrdinalIgnoreCase))
        {
            var appPri = Path.Combine(context.InstallRoot, "YMhutBox.pri");
            if (File.Exists(appPri))
            {
                return item with
                {
                    Severity = StartupCheckSeverity.Info,
                    Status = StartupCheckStatus.Passed,
                    Name = "resources.pri / YMhutBox.pri",
                    Detail = "检测到当前 WinUI 开发/运行输出使用 YMhutBox.pri，资源索引可用；旧记录仅供参考。",
                    Path = appPri
                };
            }
        }

        if (item.Id.Equals("manifest", StringComparison.OrdinalIgnoreCase) &&
            !File.Exists(context.ManifestPath) &&
            context.ManifestIdentity.StartsWith("no-manifest:", StringComparison.OrdinalIgnoreCase))
        {
            return item with
            {
                Severity = StartupCheckSeverity.Info,
                Status = StartupCheckStatus.Skipped,
                Detail = "当前安装目录未包含安装清单；按当前目录实际文件执行降噪检查，旧记录仅供参考。",
                Path = context.ManifestPath
            };
        }

        return item;
    }

    private static StartupCheckReportSummary MarkCurrentInstall(StartupCheckReportSummary summary, InstallRootContext context)
    {
        var installIdentity = string.IsNullOrWhiteSpace(summary.InstallIdentity)
            ? InstallRootContext.BuildInstallIdentity(summary.InstallRoot, summary.ManifestIdentity)
            : summary.InstallIdentity;
        var isCurrent = string.Equals(installIdentity, context.InstallIdentity, StringComparison.OrdinalIgnoreCase);
        return summary with
        {
            InstallIdentity = installIdentity,
            IsCurrentInstall = isCurrent,
            SupersededByCurrentInstall = !isCurrent,
            VisibleIssueCount = isCurrent ? summary.VisibleIssueCount : 0,
            CheckBasis = string.IsNullOrWhiteSpace(summary.CheckBasis)
                ? $"installRoot={summary.InstallRoot}; manifest={summary.ManifestIdentity}"
                : summary.CheckBasis
        };
    }

    private static StartupCheckItem RecheckItem(StartupCheckItem item, InstallRootContext context)
    {
        var path = ResolveCurrentItemPath(item, context);
        if (string.IsNullOrWhiteSpace(path))
        {
            return item with
            {
                Severity = StartupCheckSeverity.Info,
                Status = StartupCheckStatus.Skipped,
                Detail = "No concrete path is attached to this item."
            };
        }

        var passed = RecheckPathForItem(item.Id, path);
        return item with
        {
            Severity = passed ? StartupCheckSeverity.Info : item.Severity,
            Status = passed ? StartupCheckStatus.Passed : item.Status,
            Detail = passed
                ? "Current check passed. The old record is kept for reference only."
                : "Current check still does not pass for this path.",
            Path = path
        };
    }

    private static string? ResolveCurrentItemPath(StartupCheckItem item, InstallRootContext context)
    {
        if (item.Id.StartsWith("file:", StringComparison.OrdinalIgnoreCase))
        {
            var relative = item.Id["file:".Length..].Replace('/', Path.DirectorySeparatorChar);
            return Path.Combine(context.InstallRoot, relative);
        }

        if (item.Id == "manifest")
        {
            return context.ManifestPath;
        }

        if (item.Id == "install-root")
        {
            return context.InstallRoot;
        }

        if (item.Id.StartsWith("lang:", StringComparison.OrdinalIgnoreCase) &&
            !item.Id.StartsWith("lang:legacy", StringComparison.OrdinalIgnoreCase) &&
            !item.Id.StartsWith("lang:root:", StringComparison.OrdinalIgnoreCase))
        {
            return Path.Combine(context.InstallRoot, "lang", item.Id["lang:".Length..]);
        }

        if (item.Id == "lang:legacy-resources")
        {
            return Path.Combine(context.InstallRoot, "resources", "lang");
        }

        if (item.Id.StartsWith("lang:root:", StringComparison.OrdinalIgnoreCase))
        {
            return Path.Combine(context.InstallRoot, item.Id["lang:root:".Length..]);
        }

        if (item.Id is "tools:root" or "tools:launchables")
        {
            return Path.Combine(context.InstallRoot, "Tools");
        }

        if (item.Id is "metadata:root" or "metadata:json")
        {
            return Path.Combine(context.InstallRoot, "Metadata");
        }

        return item.Path;
    }

    private static bool RecheckPathForItem(string itemId, string path)
    {
        if (itemId == "lang:legacy-resources" ||
            itemId.StartsWith("lang:root:", StringComparison.OrdinalIgnoreCase) ||
            itemId.StartsWith("userdata:", StringComparison.OrdinalIgnoreCase))
        {
            return !Directory.Exists(path);
        }

        if (itemId.StartsWith("lang:", StringComparison.OrdinalIgnoreCase))
        {
            return Directory.Exists(path) &&
                (Directory.EnumerateFiles(path, "*.mui", SearchOption.AllDirectories).Any() ||
                 Directory.EnumerateFiles(path, "*.resources.dll", SearchOption.AllDirectories).Any());
        }

        if (itemId is "install-root" or "tools:root" or "metadata:root")
        {
            return Directory.Exists(path);
        }

        if (itemId == "tools:launchables")
        {
            return Directory.Exists(path) &&
                Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)
                    .Any(file => LaunchableExtensions.Contains(Path.GetExtension(file), StringComparer.OrdinalIgnoreCase));
        }

        if (itemId == "metadata:json")
        {
            return Directory.Exists(path) &&
                Directory.EnumerateFiles(path, "*.json", SearchOption.AllDirectories).Any();
        }

        if (itemId.StartsWith("file:", StringComparison.OrdinalIgnoreCase) || itemId == "manifest")
        {
            return File.Exists(path);
        }

        return File.Exists(path) || Directory.Exists(path);
    }

    private static StartupCheckItem Passed(string id, string name, string detail, string? path = null)
        => new(id, name, StartupCheckSeverity.Info, StartupCheckStatus.Passed, detail, path);

    private static StartupCheckItem Missing(string id, string name, StartupCheckSeverity severity, string detail, string? path = null)
        => new(id, name, severity, StartupCheckStatus.Missing, detail, path);

    private static StartupCheckItem Failed(string id, string name, StartupCheckSeverity severity, string detail, string? path = null)
        => new(id, name, severity, StartupCheckStatus.Failed, detail, path);

    private static StartupCheckItem Skipped(string id, string name, string detail, string? path = null)
        => new(id, name, StartupCheckSeverity.Info, StartupCheckStatus.Skipped, detail, path);

    private static string Normalize(string relativePath)
        => relativePath.Trim().Replace('\\', '/').TrimStart('/');

    private static bool LooksLikeCultureName(string name)
    {
        try
        {
            var culture = CultureInfo.GetCultureInfo(name);
            return !string.IsNullOrWhiteSpace(culture.Name) &&
                string.Equals(culture.Name, name, StringComparison.OrdinalIgnoreCase);
        }
        catch (CultureNotFoundException)
        {
            return false;
        }
    }

    private static string Sanitize(string value)
        => value.ReplaceLineEndings(" ").Trim();
}
