using YMhut.Box.Core.App;
using YMhut.Box.Core.Downloads;
using YMhut.Box.Core.Logging;
using YMhut.Box.Core.Plugins;
using YMhut.Box.Core.Settings;
using YMhut.Box.Core.Startup;
using YMhut.Box.Core.Tools;

namespace YMhut.Box.WinUI.Services;

public interface IStartupInitializationService
{
    StartupInitializationSnapshot? CurrentSnapshot { get; }

    Task<StartupInitializationSnapshot> InitializeAsync(CancellationToken cancellationToken = default);

    Task<StartupInitializationSnapshot> InitializeAsync(
        IProgress<StartupInitializationProgress>? progress,
        CancellationToken cancellationToken = default);
}

public sealed record StartupInitializationProgress(
    string Status,
    double Progress,
    bool IsIndeterminate = false,
    string? Theme = null,
    string StageId = "",
    string StageName = "",
    int StepIndex = 0,
    int StepCount = 0,
    string? Detail = null,
    StartupCheckSeverity Severity = StartupCheckSeverity.Info,
    bool IsRepairStep = false);

public sealed class StartupInitializationService(
    AppPaths paths,
    ISettingsService settingsService,
    ILogService logService,
    IPluginStateStore pluginStateStore,
    IDownloadManagerService downloadManager,
    IExternalToolCatalogService externalToolCatalog,
    IBuiltinReferenceToolCatalog builtinToolCatalog,
    IInstallIntegrityCheckService integrityCheckService) : IStartupInitializationService
{
    private readonly SemaphoreSlim _gate = new(1, 1);

    public StartupInitializationSnapshot? CurrentSnapshot { get; private set; }

    public Task<StartupInitializationSnapshot> InitializeAsync(CancellationToken cancellationToken = default)
        => InitializeAsync(null, cancellationToken);

    public async Task<StartupInitializationSnapshot> InitializeAsync(
        IProgress<StartupInitializationProgress>? progress,
        CancellationToken cancellationToken = default)
    {
        if (CurrentSnapshot is not null)
        {
            ReportCompleted(progress, CurrentSnapshot);
            return CurrentSnapshot;
        }

        await _gate.WaitAsync(cancellationToken).ConfigureAwait(false);
        try
        {
            if (CurrentSnapshot is not null)
            {
                ReportCompleted(progress, CurrentSnapshot);
                return CurrentSnapshot;
            }

            var startedAt = DateTimeOffset.Now;
            var settings = settingsService.Current;
            StartupCheckReport? preflight = null;
            int toolCount = 0;

            StartupTrace.Write("StartupInitialization:start");
            var pipeline = new StartupInitializationPipeline(CreateStages(
                startedAt,
                () => settings,
                value => settings = value,
                value => preflight = value,
                value => toolCount = value));

            var pipelineProgress = new Progress<StartupInitializationStageProgress>(stage =>
            {
                progress?.Report(new StartupInitializationProgress(
                    string.IsNullOrWhiteSpace(stage.Detail) ? stage.StageName : stage.Detail,
                    stage.Progress,
                    stage.IsIndeterminate,
                    settings.Theme,
                    stage.StageId,
                    stage.StageName,
                    stage.StepIndex,
                    stage.StepCount,
                    stage.Detail,
                    stage.Severity,
                    stage.IsRepairStep));
            });

            await pipeline.RunAsync(pipelineProgress, cancellationToken).ConfigureAwait(false);

            if (preflight is null)
            {
                throw new InvalidOperationException("Startup preflight did not produce a report.");
            }

            CurrentSnapshot = new StartupInitializationSnapshot(
                startedAt,
                DateTimeOffset.Now,
                preflight,
                toolCount,
                preflight.InstallRoot);

            await logService.WriteAsync(
                preflight.HasCriticalIssues ? "Error" : preflight.HasVisibleIssues ? "Warning" : "Information",
                "startup",
                "启动预热完成",
                $"tools={toolCount}; critical={preflight.CriticalIssueCount}; issues={preflight.IssueCount}; visible={preflight.VisibleIssueCount}",
                cancellationToken).ConfigureAwait(false);
            StartupTrace.Write($"StartupInitialization:ready:tools={toolCount}:critical={preflight.CriticalIssueCount}");

            ReportCompleted(progress, CurrentSnapshot);
            return CurrentSnapshot;
        }
        catch (Exception exception)
        {
            StartupTrace.Write($"StartupInitialization:failed:{exception.GetType().Name}");
            CrashLog.Write(exception);
            throw;
        }
        finally
        {
            _gate.Release();
        }
    }

    private IEnumerable<StartupInitializationStage> CreateStages(
        DateTimeOffset startedAt,
        Func<AppSettings> getSettings,
        Action<AppSettings> setSettings,
        Action<StartupCheckReport> setPreflight,
        Action<int> setToolCount)
    {
        yield return Stage("prepare-user-data", T("准备用户目录", "Preparing user folders"), 8, true, (context, token) =>
        {
            context.Report(0.35, T("正在准备用户数据、缓存和日志目录...", "Preparing data, cache, and log folders..."));
            paths.EnsureCreated();
            context.Report(1, T("用户目录已准备完成。", "User folders are ready."));
            return Task.CompletedTask;
        });

        yield return Stage("settings", T("读取设置", "Reading settings"), 10, true, async (context, token) =>
        {
            context.Report(0.25, T("正在读取本地设置...", "Reading local settings..."));
            var loaded = await settingsService.LoadAsync(token).ConfigureAwait(false);
            setSettings(loaded);
            context.Report(1, T("本地设置已载入。", "Local settings loaded."));
        });

        yield return Stage("database", T("初始化主 SQLite", "Initializing main SQLite"), 10, true, async (context, token) =>
        {
            context.Report(0.25, T("正在初始化日志与主数据库...", "Initializing logs and main database..."));
            await logService.WriteAsync(
                "Information",
                "startup",
                "启动预热开始",
                $"language={getSettings().Language}; started={startedAt:O}",
                token).ConfigureAwait(false);
            context.Report(1, T("主 SQLite 可写。", "Main SQLite is writable."));
        });

        yield return Stage("language-layout", T("检查语言资源", "Checking language resources"), 8, true, (context, token) =>
        {
            var installRoot = InstallLayoutPaths.ResolveInstallRoot();
            var zh = Path.Combine(installRoot, "lang", "zh-CN");
            var en = Path.Combine(installRoot, "lang", "en-US");
            var ok = Directory.Exists(zh) && Directory.Exists(en);
            context.Report(
                1,
                ok
                    ? T("语言资源布局已准备。", "Language layout is ready.")
                    : T("语言资源布局将在快速预检中复核。", "Language layout will be verified by fast preflight."),
                ok ? StartupCheckSeverity.Info : StartupCheckSeverity.Warning);
            return Task.CompletedTask;
        });

        yield return Stage("payload-cleanup", T("清理用户目录残留", "Cleaning user data remnants"), 10, false, (context, token) =>
        {
            context.Report(0.2, T("正在清理旧版 runtime、Tools 和 Metadata 残留...", "Cleaning legacy runtime, Tools, and Metadata remnants..."), isRepairStep: true);
            var removed = paths.CleanupUserPayloadDirectories();
            context.Report(
                1,
                removed.Count == 0
                    ? T("未发现用户目录中的大型程序布局副本。", "No payload copies were found in the user data folder.")
                    : T($"已清理 {removed.Count} 个用户目录残留。", $"{removed.Count} user data remnants cleaned."),
                isRepairStep: true);
            return Task.CompletedTask;
        });

        yield return Stage("plugin-state", T("恢复插件状态", "Restoring plugin state"), 8, false, async (context, token) =>
        {
            context.Report(0.35, T("正在恢复插件状态...", "Restoring plugin state..."));
            _ = await pluginStateStore.GetStateAsync("__startup__", token).ConfigureAwait(false);
            context.Report(1, T("插件状态已就绪。", "Plugin state is ready."));
        });

        yield return Stage("download-queue", T("初始化下载队列", "Initializing download queue"), 8, true, async (context, token) =>
        {
            context.Report(0.3, T("正在初始化下载队列...", "Initializing download queue..."));
            await downloadManager.InitializeAsync(token).ConfigureAwait(false);
            context.Report(1, T("下载队列已就绪。", "Download queue is ready."));
        });

        yield return Stage("fast-preflight", T("执行快速预检", "Running fast preflight"), 20, true, async (context, token) =>
        {
            context.Report(0.15, T("正在复核安装目录、语言资源和关键文件...", "Verifying install root, language resources, and critical files..."));
            var report = await integrityCheckService.RunFastPreflightAsync(token).ConfigureAwait(false);
            setPreflight(report);
            context.Report(
                1,
                report.HasVisibleIssues
                    ? T("快速预检完成：发现问题，详情已写入结果页。", "Fast preflight complete: issues found and written to results.")
                    : T("快速预检完成：未发现问题。", "Fast preflight complete: no issues found."),
                report.HasVisibleIssues ? StartupCheckSeverity.Warning : StartupCheckSeverity.Info);
        });

        yield return Stage("tool-catalog", T("扫描工具目录", "Scanning tool catalog"), 12, false, async (context, token) =>
        {
            context.Report(0.25, T("正在扫描内置与随包工具...", "Scanning built-in and bundled tools..."));
            var externalTools = await externalToolCatalog.GetModulesAsync(token).ConfigureAwait(false);
            var builtinTools = builtinToolCatalog.GetModules();
            var count = ToolCatalog.DefaultModules().Count() + builtinTools.Count + externalTools.Count;
            setToolCount(count);
            context.Report(1, T($"工具目录已就绪：{count} 个工具。", $"Tool catalog ready: {count} tools."));
        });

        yield return Stage("snapshot", T("生成启动快照", "Preparing startup snapshot"), 6, true, (context, token) =>
        {
            context.Report(1, T("启动快照已生成。", "Startup snapshot prepared."));
            return Task.CompletedTask;
        });
    }

    private static StartupInitializationStage Stage(
        string id,
        string displayName,
        double weight,
        bool critical,
        Func<StartupInitializationStageContext, CancellationToken, Task> executeAsync)
        => new(id, displayName, weight, critical, executeAsync);

    private static void ReportCompleted(
        IProgress<StartupInitializationProgress>? progress,
        StartupInitializationSnapshot snapshot)
    {
        progress?.Report(new StartupInitializationProgress(
            snapshot.HasVisibleStartupIssue
                ? T("启动自检完成：发现问题，详情可在结果页查看。", "Startup check complete: issues found. Details are available on the results page.")
                : T("启动自检完成：未发现问题。", "Startup check complete: no issues found."),
            100,
            false,
            null,
            "complete",
            T("启动完成", "Startup complete"),
            10,
            10,
            null,
            snapshot.HasVisibleStartupIssue ? StartupCheckSeverity.Warning : StartupCheckSeverity.Info));
    }

    private static string T(string zh, string en) => AppLocalizer.T(zh, en);
}
