using System.Diagnostics;
using Microsoft.UI.Text;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Windows.System;
using YMhut.Box.Core.DevEnvironments;
using YMhut.Box.Core.Downloads;
using YMhut.Box.Core.Tools;
using YMhut.Box.WinUI.Services;
using YMhut.Box.WinUI.ViewModels.Tools;

namespace YMhut.Box.WinUI.Views.Tools;

public sealed class DevEnvironmentConfigToolViewModel(IToolModule module) : AdaptiveToolViewModel(module);

public sealed class DevEnvironmentConfigToolPage : ToolPageBase
{
    private readonly IToolModule _module;
    private readonly Action? _goBack;
    private readonly IDevEnvironmentDetectionService _detection = AppServices.GetRequiredService<IDevEnvironmentDetectionService>();
    private readonly IDevEnvironmentCatalogService _catalog = AppServices.GetRequiredService<IDevEnvironmentCatalogService>();
    private readonly IDownloadManagerService _downloads = AppServices.GetRequiredService<IDownloadManagerService>();
    private readonly StackPanel _environmentList = new() { Spacing = 12 };
    private readonly TextBlock _statusText = ModernUi.Text(AppLocalizer.T("准备检测开发环境。", "Ready to detect development environments."), 14, foreground: ModernUi.TextSecondary);
    private readonly Dictionary<string, ComboBox> _versionBoxes = new(StringComparer.OrdinalIgnoreCase);
    private readonly Dictionary<string, ComboBox> _sourceBoxes = new(StringComparer.OrdinalIgnoreCase);
    private readonly Dictionary<string, Button> _quickButtons = new(StringComparer.OrdinalIgnoreCase);
    private readonly Dictionary<string, Button> _sourceButtons = new(StringComparer.OrdinalIgnoreCase);
    private IReadOnlyDictionary<string, DetectedDevEnvironment> _detected = new Dictionary<string, DetectedDevEnvironment>();
    private IReadOnlyDictionary<string, IReadOnlyList<DevEnvironmentVersion>> _versions = new Dictionary<string, IReadOnlyList<DevEnvironmentVersion>>();

    public DevEnvironmentConfigToolPage(IToolModule module, DevEnvironmentConfigToolViewModel viewModel, Action? goBack = null)
    {
        _module = module;
        _goBack = goBack;
        BindModule(module);
        Background = ModernUi.AppBackground;
        Content = BuildContent();
        Loaded += async (_, _) => await ReloadAsync();
    }

    private UIElement BuildContent()
    {
        var root = new StackPanel
        {
            Padding = new Thickness(28, 22, 28, 28),
            Spacing = 16
        };

        var back = ModernUi.IconButton("\uE72B", AppLocalizer.T("返回工具箱", "Back to toolbox"), () => _goBack?.Invoke());
        var reload = ModernUi.PillButton(AppLocalizer.T("重新检测", "Detect again"), "\uE895", async () => await ReloadAsync(), primary: true);
        var downloads = ModernUi.PillButton(AppLocalizer.T("打开下载管理", "Open downloads"), "\uE896", OpenDownloadManager);

        var header = new Grid { ColumnSpacing = 14 };
        header.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
        header.ColumnDefinitions.Add(new ColumnDefinition());
        header.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
        header.Children.Add(back);
        var titlePanel = new StackPanel
        {
            Spacing = 4,
            Children =
            {
                ModernUi.Text(AppLocalizer.T("开发环境配置", "Development Environment Setup"), 28, FontWeights.SemiBold),
                ModernUi.Text(AppLocalizer.T("检测本机 Go、Python、Java、Docker、MySQL、Node.js、.NET、Git、Rust 和 CMake，并从官方来源下载版本。", "Detect local Go, Python, Java, Docker, MySQL, Node.js, .NET, Git, Rust, and CMake, then download versions from official sources."), 14, foreground: ModernUi.TextSecondary, maxLines: 2),
                _statusText
            }
        };
        Grid.SetColumn(titlePanel, 1);
        header.Children.Add(titlePanel);

        var actionRow = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 8, Children = { reload, downloads } };
        Grid.SetColumn(actionRow, 2);
        header.Children.Add(actionRow);

        root.Children.Add(ModernUi.Card(header, new Thickness(18), radius: 8));
        root.Children.Add(_environmentList);

        return new ScrollViewer
        {
            HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled,
            VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
            Content = root
        };
    }

    private async Task ReloadAsync()
    {
        _statusText.Text = AppLocalizer.T("正在检测本机环境并读取官方版本信息...", "Detecting local environments and reading official version metadata...");
        _environmentList.Children.Clear();
        _environmentList.Children.Add(ModernUi.Card(ModernUi.Text(AppLocalizer.T("检测中...", "Detecting..."), 14, foreground: ModernUi.TextSecondary), new Thickness(14), radius: 8));

        try
        {
            var detected = await _detection.DetectAsync();
            _detected = detected.ToDictionary(item => item.Id, StringComparer.OrdinalIgnoreCase);

            var versionPairs = await Task.WhenAll(_catalog.Definitions.Select(async definition =>
            {
                var versions = await _catalog.GetVersionsAsync(definition.Id);
                return (definition.Id, Versions: versions);
            }));
            _versions = versionPairs.ToDictionary(item => item.Id, item => item.Versions, StringComparer.OrdinalIgnoreCase);

            Render();
        }
        catch (Exception exception)
        {
            _statusText.Text = AppLocalizer.T("开发环境检测失败。", "Development environment detection failed.");
            _environmentList.Children.Clear();
            _environmentList.Children.Add(ModernUi.Card(
                ModernUi.Text(AppLocalizer.SanitizeSensitiveText(exception.Message, 180), 14, foreground: ModernUi.Danger),
                new Thickness(14),
                radius: 8));
        }
    }

    private void Render()
    {
        _versionBoxes.Clear();
        _sourceBoxes.Clear();
        _quickButtons.Clear();
        _sourceButtons.Clear();
        _environmentList.Children.Clear();
        var installed = _detected.Values.Count(item => item.IsInstalled);
        _statusText.Text = AppLocalizer.T($"已检测到 {installed} 个开发环境。", $"{installed} development environments detected.");

        foreach (var definition in _catalog.Definitions)
        {
            _environmentList.Children.Add(BuildEnvironmentCard(definition));
        }
    }

    private Border BuildEnvironmentCard(DevEnvironmentDefinition definition)
    {
        _detected.TryGetValue(definition.Id, out var detected);
        _versions.TryGetValue(definition.Id, out var versions);
        versions ??= [];

        var box = new ComboBox
        {
            MinWidth = 190,
            PlaceholderText = AppLocalizer.T("选择版本", "Select version"),
            HorizontalAlignment = HorizontalAlignment.Stretch
        };
        foreach (var version in versions.Take(30))
        {
            box.Items.Add(new ComboBoxItem
            {
                Content = VersionLabel(version),
                Tag = version
            });
        }

        if (box.Items.Count > 0)
        {
            box.SelectedIndex = 0;
        }

        _versionBoxes[definition.Id] = box;
        var sourceBox = new ComboBox
        {
            MinWidth = 220,
            PlaceholderText = AppLocalizer.T("选择下载源", "Select source"),
            HorizontalAlignment = HorizontalAlignment.Stretch
        };
        _sourceBoxes[definition.Id] = sourceBox;

        var quick = ModernUi.PillButton(AppLocalizer.T("快速安装", "Quick install"), "\uE896", async () => await QueueDownloadAsync(definition, DevEnvironmentInstallMode.QuickInstall), primary: true);
        var source = ModernUi.PillButton(AppLocalizer.T("源码/编译", "Source build"), "\uE756", async () => await QueueDownloadAsync(definition, DevEnvironmentInstallMode.SourceBuild));
        var official = ModernUi.IconButton("\uE8A7", AppLocalizer.T("打开官网", "Open official site"), async () => await Launcher.LaunchUriAsync(new Uri(definition.OfficialHome)));
        _quickButtons[definition.Id] = quick;
        _sourceButtons[definition.Id] = source;

        var top = new Grid { ColumnSpacing = 14 };
        top.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
        top.ColumnDefinitions.Add(new ColumnDefinition());
        top.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
        top.Children.Add(ModernUi.IconTile("\uE943", 42, ModernUi.AccentSoft, ModernUi.Accent, 18));
        var titlePanel = new StackPanel
        {
            Spacing = 3,
            Children =
            {
                ModernUi.Text(definition.Name, 18, FontWeights.SemiBold, maxLines: 1),
                ModernUi.Text(DetectionLine(detected), 13, foreground: detected?.IsInstalled == true ? ModernUi.Success : ModernUi.TextSecondary, maxLines: 2)
            }
        };
        Grid.SetColumn(titlePanel, 1);
        top.Children.Add(titlePanel);
        var actions = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 8, Children = { official } };
        Grid.SetColumn(actions, 2);
        top.Children.Add(actions);

        var controls = new Grid { ColumnSpacing = 10, RowSpacing = 10 };
        controls.ColumnDefinitions.Add(new ColumnDefinition());
        controls.ColumnDefinitions.Add(new ColumnDefinition());
        controls.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
        controls.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
        controls.Children.Add(box);
        Grid.SetColumn(sourceBox, 1);
        controls.Children.Add(sourceBox);
        Grid.SetColumn(quick, 2);
        Grid.SetColumn(source, 3);
        controls.Children.Add(quick);
        controls.Children.Add(source);
        box.SelectionChanged += (_, _) => RefreshSourceChoices(definition.Id);
        sourceBox.SelectionChanged += (_, _) => RefreshActionState(definition.Id);
        RefreshSourceChoices(definition.Id);

        return ModernUi.Card(new StackPanel
        {
            Spacing = 12,
            Children =
            {
                top,
                ModernUi.Text(AppLocalizer.T($"版本来源：{definition.VersionSource}", $"Version source: {definition.VersionSource}"), 12, foreground: ModernUi.TextSecondary, maxLines: 1),
                controls
            }
        }, new Thickness(16), radius: 8);
    }

    private async Task QueueDownloadAsync(DevEnvironmentDefinition definition, DevEnvironmentInstallMode mode)
    {
        var version = SelectedVersion(definition.Id);
        if (version is null)
        {
            ToastService.Show(AppLocalizer.T("没有可下载的版本。", "No downloadable version is available."), ToastKind.Warning);
            return;
        }

        var candidate = SelectedCandidate(definition.Id, mode);
        if (candidate is null)
        {
            ToastService.Show(AppLocalizer.T("请选择可用的下载源。", "Select an available download source."), ToastKind.Warning);
            return;
        }

        if (string.IsNullOrWhiteSpace(candidate.Source.Url) ||
            !Uri.TryCreate(candidate.Source.Url, UriKind.Absolute, out var uri) ||
            uri.Scheme is not ("http" or "https"))
        {
            await Launcher.LaunchUriAsync(new Uri(definition.OfficialHome));
            ToastService.Show(AppLocalizer.T("该来源需要在官网手动选择下载。", "This source requires manual selection on the official site."), ToastKind.Warning);
            return;
        }

        var plan = _catalog.CreateInstallPlan(definition.Id, version, candidate);
        var item = await _downloads.EnqueueAsync(
            candidate.Source,
            new DownloadOptions(
                InstallCommand: mode == DevEnvironmentInstallMode.QuickInstall ? "installer" : null,
                InstallArguments: plan.InstallArguments,
                IsInstaller: mode == DevEnvironmentInstallMode.QuickInstall,
                DeleteAfterInstall: mode == DevEnvironmentInstallMode.QuickInstall));

        ToastService.Show(AppLocalizer.T("已加入下载管理。", "Added to Download Manager."), ToastKind.Success);
        if (mode == DevEnvironmentInstallMode.SourceBuild)
        {
            OpenBuildTerminal(plan, item);
        }
    }

    private DevEnvironmentVersion? SelectedVersion(string id)
    {
        if (!_versionBoxes.TryGetValue(id, out var box) ||
            box.SelectedItem is not ComboBoxItem item ||
            item.Tag is not DevEnvironmentVersion version)
        {
            return null;
        }

        return version;
    }

    private DevEnvironmentDownloadCandidate? SelectedCandidate(string id, DevEnvironmentInstallMode mode)
    {
        if (!_sourceBoxes.TryGetValue(id, out var box) ||
            box.SelectedItem is not ComboBoxItem item ||
            item.Tag is not DevEnvironmentDownloadCandidate candidate)
        {
            return SelectedVersion(id)?.AllCandidates.FirstOrDefault(candidate => candidate.Mode == mode);
        }

        if (candidate.Mode == mode)
        {
            return candidate;
        }

        return SelectedVersion(id)?.AllCandidates.FirstOrDefault(candidate => candidate.Mode == mode);
    }

    private void RefreshSourceChoices(string id)
    {
        if (!_sourceBoxes.TryGetValue(id, out var box))
        {
            return;
        }

        box.Items.Clear();
        var version = SelectedVersion(id);
        if (version is not null)
        {
            foreach (var candidate in version.AllCandidates)
            {
                box.Items.Add(new ComboBoxItem
                {
                    Content = CandidateLabel(candidate),
                    Tag = candidate
                });
            }
        }

        if (box.Items.Count > 0)
        {
            box.SelectedIndex = 0;
        }

        RefreshActionState(id);
    }

    private void RefreshActionState(string id)
    {
        var version = SelectedVersion(id);
        var hasQuick = version?.AllCandidates.Any(candidate => candidate.Mode == DevEnvironmentInstallMode.QuickInstall) == true;
        var hasSource = version?.AllCandidates.Any(candidate => candidate.Mode == DevEnvironmentInstallMode.SourceBuild) == true &&
            !string.Equals(id, "docker", StringComparison.OrdinalIgnoreCase);
        if (_quickButtons.TryGetValue(id, out var quick))
        {
            quick.IsEnabled = hasQuick;
        }
        if (_sourceButtons.TryGetValue(id, out var source))
        {
            source.Visibility = hasSource ? Visibility.Visible : Visibility.Collapsed;
            source.IsEnabled = hasSource;
        }
    }

    private static void OpenBuildTerminal(DevEnvironmentInstallPlan plan, DownloadItem item)
    {
        try
        {
            var script = Path.Combine(Path.GetTempPath(), $"ymhut-build-{plan.EnvironmentId}-{Guid.NewGuid():N}.cmd");
            File.WriteAllLines(script, [
                "@echo off",
                "chcp 65001 > nul",
                $"echo {plan.EnvironmentName} {plan.Version.Version}",
                $"echo Source download target: {item.TargetPath}",
                "echo.",
                "if not exist \"%~dp0\" mkdir \"%~dp0\"",
                $"set \"ARCHIVE={item.TargetPath}\"",
                $"set \"WORKDIR=%USERPROFILE%\\YMhutBuilds\\{plan.EnvironmentId}-{plan.Version.Version}\"",
                "echo Waiting for source archive...",
                ":wait_download",
                "if not exist \"%ARCHIVE%\" (timeout /t 2 > nul & goto wait_download)",
                "mkdir \"%WORKDIR%\" 2>nul",
                "cd /d \"%WORKDIR%\"",
                "echo.",
                "echo Build recipe:",
                $"echo {plan.BuildRecipe.Replace(Environment.NewLine, " & echo ")}",
                "echo.",
                "echo Extract the archive here, review prerequisites, then run the vendor build commands above.",
                "echo.",
                "pause"
            ]);
            Process.Start(new ProcessStartInfo
            {
                FileName = "cmd.exe",
                Arguments = $"/k \"{script}\"",
                UseShellExecute = true
            });
        }
        catch (Exception exception)
        {
            ToastService.Show(AppLocalizer.SanitizeSensitiveText(exception.Message, 140), ToastKind.Warning);
        }
    }

    private static string DetectionLine(DetectedDevEnvironment? detected)
    {
        if (detected is null || !detected.IsInstalled)
        {
            return AppLocalizer.T("未检测到，可选择官方版本下载。", "Not detected. Choose an official version to download.");
        }

        var path = string.IsNullOrWhiteSpace(detected.Path) ? detected.Source : detected.Path;
        return string.IsNullOrWhiteSpace(path)
            ? AppLocalizer.T($"已安装：{detected.Version}", $"Installed: {detected.Version}")
            : AppLocalizer.T($"已安装：{detected.Version} · {path}", $"Installed: {detected.Version} · {path}");
    }

    private static string VersionLabel(DevEnvironmentVersion version)
    {
        return version.PublishedAt is DateTimeOffset date
            ? $"{version.Version} · {date:yyyy-MM-dd}"
            : version.Version;
    }

    private static string CandidateLabel(DevEnvironmentDownloadCandidate candidate)
    {
        var size = candidate.Source.SizeBytes is long bytes ? $" · {DownloadFormat.FormatBytes(bytes)}" : string.Empty;
        var region = string.IsNullOrWhiteSpace(candidate.Region) ? string.Empty : $" · {candidate.Region}";
        var mode = candidate.Mode == DevEnvironmentInstallMode.SourceBuild
            ? AppLocalizer.T("源码", "Source")
            : AppLocalizer.T("安装包", "Installer");
        return $"{mode} · {candidate.SourceType}{region}{size}";
    }

    private static void OpenDownloadManager()
    {
        if (App.CurrentWindow is MainWindow mainWindow)
        {
            mainWindow.ShowDownloadManagerPage();
        }
    }
}
