using Microsoft.UI.Text;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using WinRT.Interop;
using Windows.ApplicationModel.DataTransfer;
using Windows.Storage.Pickers;
using Windows.System;
using YMhut.Box.Core.Downloads;
using YMhut.Box.WinUI.Services;

namespace YMhut.Box.WinUI.Views;

public sealed class DownloadManagerPage : Page
{
    private readonly IDownloadManagerService _downloads = AppServices.GetRequiredService<IDownloadManagerService>();
    private readonly IDirectDownloadValidator _validator = AppServices.GetRequiredService<IDirectDownloadValidator>();
    private readonly StackPanel _activeList = new() { Spacing = 10 };
    private readonly StackPanel _completedList = new() { Spacing = 10 };
    private readonly StackPanel _failedList = new() { Spacing = 10 };
    private readonly TextBlock _summaryText = ModernUi.Text("", 14, FontWeights.SemiBold, ModernUi.TextSecondary);
    private readonly TextBlock _locationText = ModernUi.Text("", 12, foreground: ModernUi.TextSecondary, maxLines: 1);
    private readonly TextBox _urlBox = new()
    {
        PlaceholderText = AppLocalizer.T("粘贴下载链接", "Paste a download URL"),
        MinWidth = 0
    };
    private readonly TextBox _fileNameBox = new()
    {
        PlaceholderText = AppLocalizer.T("文件名（可选）", "File name (optional)"),
        MinWidth = 0
    };
    private string? _saveAsPath;

    public DownloadManagerPage()
    {
        Background = ModernUi.AppBackground;
        Content = BuildContent();
        Loaded += DownloadManagerPage_Loaded;
        Unloaded += (_, _) => _downloads.ItemsChanged -= Downloads_ItemsChanged;
    }

    private async void DownloadManagerPage_Loaded(object sender, RoutedEventArgs e)
    {
        _downloads.ItemsChanged -= Downloads_ItemsChanged;
        _downloads.ItemsChanged += Downloads_ItemsChanged;
        await _downloads.InitializeAsync();
        Refresh();
    }

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

        var clear = ModernUi.PillButton(AppLocalizer.T("清理完成", "Clear completed"), "\uE74D", async () => await _downloads.ClearCompletedAsync());
        var header = new Grid { ColumnSpacing = 16 };
        header.ColumnDefinitions.Add(new ColumnDefinition());
        header.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
        header.Children.Add(new StackPanel
        {
            Spacing = 4,
            Children =
            {
                ModernUi.Text(AppLocalizer.T("下载管理", "Download Manager"), 30, FontWeights.SemiBold),
                ModernUi.Text(AppLocalizer.T("集中托管工具包、开发环境安装包和手动下载任务。", "Manage tool packages, development installers, and manual downloads in one queue."), 14, foreground: ModernUi.TextSecondary, maxLines: 2),
                _summaryText
            }
        });
        Grid.SetColumn(clear, 1);
        header.Children.Add(clear);
        root.Children.Add(ModernUi.Card(header, new Thickness(18), radius: 8));
        root.Children.Add(BuildNewDownloadPanel());

        var tabs = new TabView
        {
            IsAddTabButtonVisible = false,
            CanDragTabs = false
        };
        tabs.TabItems.Add(Tab(AppLocalizer.T("进行中", "Active"), _activeList));
        tabs.TabItems.Add(Tab(AppLocalizer.T("已完成", "Completed"), _completedList));
        tabs.TabItems.Add(Tab(AppLocalizer.T("失败", "Failed"), _failedList));
        root.Children.Add(tabs);

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

    private UIElement BuildNewDownloadPanel()
    {
        var add = ModernUi.PillButton(AppLocalizer.T("新建下载", "New download"), "\uE896", async () => await AddManualDownloadAsync(), primary: true);
        var saveAs = ModernUi.PillButton(AppLocalizer.T("另存为", "Save as"), "\uE105", async () => await PickSaveAsAsync());
        var defaultFolder = ModernUi.PillButton(AppLocalizer.T("默认位置", "Default folder"), "\uE838", async () => await PickDefaultFolderAsync());

        var form = new Grid
        {
            ColumnSpacing = 10,
            RowSpacing = 10
        };
        form.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(2, GridUnitType.Star) });
        form.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
        form.Children.Add(_urlBox);
        Grid.SetColumn(_fileNameBox, 1);
        form.Children.Add(_fileNameBox);
        var actionRow = new StackPanel
        {
            Orientation = Orientation.Horizontal,
            Spacing = 8,
            HorizontalAlignment = HorizontalAlignment.Right,
            Children = { saveAs, defaultFolder, add }
        };

        var titleGrid = new Grid { ColumnSpacing = 12 };
        titleGrid.ColumnDefinitions.Add(new ColumnDefinition());
        titleGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
        titleGrid.Children.Add(ModernUi.Text(AppLocalizer.T("新建任务", "New task"), 18, FontWeights.SemiBold));
        var concurrencyBadge = Badge(AppLocalizer.T("最多 5 个任务同时下载", "Up to 5 concurrent downloads"));
        Grid.SetColumn(concurrencyBadge, 1);
        titleGrid.Children.Add(concurrencyBadge);

        var stack = new StackPanel
        {
            Spacing = 10,
            Children =
            {
                titleGrid,
                form,
                actionRow,
                _locationText
            }
        };

        return ModernUi.Card(stack, new Thickness(18), radius: 8);
    }

    private static TabViewItem Tab(string title, UIElement content)
    {
        return new TabViewItem
        {
            Header = title,
            IsClosable = false,
            Content = new ScrollViewer
            {
                HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled,
                VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
                Content = content
            }
        };
    }

    private void Downloads_ItemsChanged(object? sender, EventArgs e)
    {
        DispatcherQueue.TryEnqueue(Refresh);
    }

    private void Refresh()
    {
        var items = _downloads.Items;
        _activeList.Children.Clear();
        _completedList.Children.Clear();
        _failedList.Children.Clear();

        foreach (var item in items.Where(item => item.State is DownloadState.Queued or DownloadState.Running or DownloadState.Paused))
        {
            _activeList.Children.Add(BuildItemCard(item));
        }

        foreach (var item in items.Where(item => item.State == DownloadState.Completed))
        {
            _completedList.Children.Add(BuildItemCard(item));
        }

        foreach (var item in items.Where(item => item.State is DownloadState.Failed or DownloadState.Canceled))
        {
            _failedList.Children.Add(BuildItemCard(item));
        }

        AddEmpty(_activeList, AppLocalizer.T("暂无进行中的下载。", "No active downloads."));
        AddEmpty(_completedList, AppLocalizer.T("暂无已完成的下载。", "No completed downloads."));
        AddEmpty(_failedList, AppLocalizer.T("暂无失败或取消的下载。", "No failed or canceled downloads."));
        var running = items.Count(item => item.State == DownloadState.Running);
        var queued = items.Count(item => item.State == DownloadState.Queued);
        _summaryText.Text = AppLocalizer.T(
            $"共 {items.Count} 个任务，运行 {running} 个，排队 {queued} 个。",
            $"{items.Count} tasks, {running} running, {queued} queued.");
        var target = _saveAsPath is null
            ? _downloads.Settings.DefaultDirectory
            : _saveAsPath;
        _locationText.Text = AppLocalizer.T(
            $"默认保存位置：{_downloads.Settings.DefaultDirectory}。当前另存为：{target}",
            $"Default folder: {_downloads.Settings.DefaultDirectory}. Current save target: {target}");
    }

    private static void AddEmpty(StackPanel panel, string text)
    {
        if (panel.Children.Count == 0)
        {
            panel.Children.Add(ModernUi.Card(ModernUi.Text(text, 14, foreground: ModernUi.TextSecondary), new Thickness(14), radius: 8, background: ModernUi.SurfaceAlt));
        }
    }

    private Border BuildItemCard(DownloadItem item)
    {
        var progress = new ProgressBar
        {
            Minimum = 0,
            Maximum = 100,
            Value = item.TotalBytes is > 0 ? Math.Clamp(item.ReceivedBytes / (double)item.TotalBytes.Value * 100, 0, 100) : 0,
            IsIndeterminate = item.State == DownloadState.Running && item.TotalBytes is not > 0,
            Height = 5
        };

        var actions = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 6, HorizontalAlignment = HorizontalAlignment.Right };
        if (item.State == DownloadState.Running)
        {
            actions.Children.Add(ModernUi.IconButton("\uE769", AppLocalizer.T("暂停", "Pause"), async () => await _downloads.PauseAsync(item.Id)));
        }
        else if (item.State == DownloadState.Paused)
        {
            actions.Children.Add(ModernUi.IconButton("\uE768", AppLocalizer.T("继续", "Resume"), async () => await _downloads.ResumeAsync(item.Id)));
        }
        else if (item.State is DownloadState.Failed or DownloadState.Canceled)
        {
            actions.Children.Add(ModernUi.IconButton("\uE895", AppLocalizer.T("重试", "Retry"), async () => await _downloads.RetryAsync(item.Id)));
        }

        if (item.State == DownloadState.Completed)
        {
            actions.Children.Add(ModernUi.IconButton("\uE8A7", AppLocalizer.T("安装 / 打开", "Install / open"), async () => await LaunchCompletedAsync(item)));
        }

        actions.Children.Add(ModernUi.IconButton("\uE838", AppLocalizer.T("打开目录", "Open folder"), async () => await OpenFolderAsync(item)));
        actions.Children.Add(ModernUi.IconButton("\uE8C8", AppLocalizer.T("复制链接", "Copy link"), () => CopyLink(item.Source.Url)));
        if (item.State is DownloadState.Running or DownloadState.Paused or DownloadState.Queued)
        {
            actions.Children.Add(ModernUi.IconButton("\uE711", AppLocalizer.T("取消", "Cancel"), async () => await _downloads.CancelAsync(item.Id)));
        }

        var top = new Grid { ColumnSpacing = 12 };
        top.ColumnDefinitions.Add(new ColumnDefinition());
        top.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
        var sourceLine = $"{StateLabel(item.State)} / {item.Source.EffectiveLabel}";
        if (!string.IsNullOrWhiteSpace(item.Source.MirrorRegion))
        {
            sourceLine += $" / {item.Source.MirrorRegion}";
        }

        top.Children.Add(new StackPanel
        {
            Spacing = 4,
            Children =
            {
                ModernUi.Text(item.Source.DisplayName, 15, FontWeights.SemiBold, maxLines: 1),
                ModernUi.Text($"{sourceLine} / {DownloadFormat.FormatBytes(item.ReceivedBytes)} / {(item.TotalBytes is long total ? DownloadFormat.FormatBytes(total) : "-")} / {DownloadFormat.FormatSpeed(item.BytesPerSecond)} / ETA {DownloadFormat.FormatEta(item.ReceivedBytes, item.TotalBytes, item.BytesPerSecond)}", 12, foreground: ModernUi.TextSecondary, maxLines: 1),
                ModernUi.Text(item.TargetPath, 12, foreground: ModernUi.TextSecondary, maxLines: 1)
            }
        });
        Grid.SetColumn(actions, 1);
        top.Children.Add(actions);

        var stack = new StackPanel { Spacing = 10, Children = { top, progress } };
        var badges = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 8 };
        if (!string.IsNullOrWhiteSpace(item.Source.Sha256))
        {
            badges.Children.Add(Badge(AppLocalizer.T("SHA256 校验", "SHA256 verified")));
        }
        if (item.DeleteAfterInstall)
        {
            badges.Children.Add(Badge(item.InstallCleanupCompleted
                ? AppLocalizer.T("安装包已清理", "Installer cleaned")
                : AppLocalizer.T("安装后清理", "Clean after install")));
        }
        if (badges.Children.Count > 0)
        {
            stack.Children.Add(badges);
        }

        if (!string.IsNullOrWhiteSpace(item.Error))
        {
            stack.Children.Add(ModernUi.Text(AppLocalizer.SanitizeSensitiveText(item.Error, 160), 12, foreground: ModernUi.Danger, maxLines: 2));
        }

        return ModernUi.Card(stack, new Thickness(14), radius: 8, background: ModernUi.Surface);
    }

    private async Task AddManualDownloadAsync()
    {
        if (await TryAddValidatedManualDownloadAsync())
        {
            return;
        }

        if (!Uri.TryCreate(_urlBox.Text.Trim(), UriKind.Absolute, out var uri) ||
            uri.Scheme is not ("http" or "https"))
        {
            ToastService.Show(AppLocalizer.T("请输入有效的 HTTP/HTTPS 下载链接。", "Enter a valid HTTP/HTTPS URL."), ToastKind.Warning);
            return;
        }

        var fileName = string.IsNullOrWhiteSpace(_fileNameBox.Text)
            ? Path.GetFileName(uri.LocalPath)
            : _fileNameBox.Text.Trim();
        if (string.IsNullOrWhiteSpace(fileName))
        {
            fileName = "download.bin";
        }

        var source = new DownloadSource(uri.AbsoluteUri, fileName, fileName, "Manual", SourceLabel: AppLocalizer.T("手动", "Manual"));
        await _downloads.EnqueueAsync(source, new DownloadOptions(TargetPath: _saveAsPath));
        _saveAsPath = null;
        _urlBox.Text = string.Empty;
        _fileNameBox.Text = string.Empty;
        ToastService.Show(AppLocalizer.T("已加入下载队列。", "Added to the download queue."), ToastKind.Success);
        Refresh();
    }

    private async Task PickSaveAsAsync()
    {
        if (App.CurrentWindow is null)
        {
            return;
        }

        var picker = new FileSavePicker
        {
            SuggestedFileName = string.IsNullOrWhiteSpace(_fileNameBox.Text) ? "download" : Path.GetFileNameWithoutExtension(_fileNameBox.Text)
        };
        picker.FileTypeChoices.Add(AppLocalizer.T("下载文件", "Download file"), [Path.GetExtension(_fileNameBox.Text) is { Length: > 1 } ext ? ext : ".bin"]);
        InitializeWithWindow.Initialize(picker, WindowNative.GetWindowHandle(App.CurrentWindow));
        var file = await picker.PickSaveFileAsync();
        if (file is not null)
        {
            _saveAsPath = file.Path;
            _fileNameBox.Text = Path.GetFileName(file.Path);
            Refresh();
        }
    }

    private async Task<bool> TryAddValidatedManualDownloadAsync()
    {
        var raw = _urlBox.Text.Trim();
        var validation = await _validator.ValidateAsync(raw);
        if (!validation.IsDirectDownload)
        {
            ToastService.Show(
                AppLocalizer.T($"这不是直接下载链接：{validation.Message}", $"This is not a direct download link: {validation.Message}"),
                ToastKind.Warning,
                TimeSpan.FromSeconds(4));
            return true;
        }

        if (!Uri.TryCreate(validation.EffectiveUrl, UriKind.Absolute, out var uri) ||
            uri.Scheme is not ("http" or "https"))
        {
            ToastService.Show(AppLocalizer.T("请输入有效的 HTTP/HTTPS 下载链接。", "Enter a valid HTTP/HTTPS URL."), ToastKind.Warning);
            return true;
        }

        var fileName = string.IsNullOrWhiteSpace(_fileNameBox.Text)
            ? FirstNonEmpty(validation.SuggestedFileName, Path.GetFileName(uri.LocalPath), "download.bin")
            : _fileNameBox.Text.Trim();

        var source = new DownloadSource(
            uri.AbsoluteUri,
            fileName,
            fileName,
            "Manual",
            SourceLabel: AppLocalizer.T("手动", "Manual"),
            OriginalUrl: string.IsNullOrWhiteSpace(validation.OriginalUrl) ? raw : validation.OriginalUrl,
            ResolvedUrl: validation.ResolvedUrl,
            ValidatedContentType: validation.ContentType);
        await _downloads.EnqueueAsync(source, new DownloadOptions(TargetPath: _saveAsPath));
        _saveAsPath = null;
        _urlBox.Text = string.Empty;
        _fileNameBox.Text = string.Empty;
        ToastService.Show(AppLocalizer.T("已加入下载队列。", "Added to the download queue."), ToastKind.Success);
        Refresh();
        return true;
    }

    private static string FirstNonEmpty(params string[] values)
    {
        return values.FirstOrDefault(value => !string.IsNullOrWhiteSpace(value)) ?? string.Empty;
    }

    private async Task PickDefaultFolderAsync()
    {
        if (App.CurrentWindow is null)
        {
            return;
        }

        var picker = new FolderPicker();
        picker.FileTypeFilter.Add("*");
        InitializeWithWindow.Initialize(picker, WindowNative.GetWindowHandle(App.CurrentWindow));
        var folder = await picker.PickSingleFolderAsync();
        if (folder is not null)
        {
            await _downloads.UpdateSettingsAsync(_downloads.Settings with { DefaultDirectory = folder.Path, MaxConcurrentDownloads = 5 });
            Refresh();
        }
    }

    private async Task LaunchCompletedAsync(DownloadItem item)
    {
        var process = DownloadManagerService.LaunchInstaller(item);
        await _downloads.MarkInstallLaunchedAsync(item.Id);
        if (process is not null && item.DeleteAfterInstall)
        {
            try
            {
                await process.WaitForExitAsync();
                await _downloads.TryCleanupAfterInstallAsync(item.Id);
            }
            catch
            {
                // Elevated installers may detach from the launched process; keep the package in that case.
            }
        }
    }

    private static async Task OpenFolderAsync(DownloadItem item)
    {
        var folder = Path.GetDirectoryName(item.TargetPath);
        if (!string.IsNullOrWhiteSpace(folder) && Directory.Exists(folder))
        {
            await Launcher.LaunchFolderPathAsync(folder);
        }
    }

    private static void CopyLink(string url)
    {
        var package = new DataPackage();
        package.SetText(url);
        Clipboard.SetContent(package);
        ToastService.Show(AppLocalizer.T("下载链接已复制", "Download link copied"), ToastKind.Success);
    }

    private static Border Badge(string text)
    {
        return ModernUi.SmallBadge(text, ModernUi.Accent, ModernUi.AccentSoft);
    }

    private static string StateLabel(DownloadState state)
    {
        return state switch
        {
            DownloadState.Queued => AppLocalizer.T("排队中", "Queued"),
            DownloadState.Running => AppLocalizer.T("下载中", "Running"),
            DownloadState.Paused => AppLocalizer.T("已暂停", "Paused"),
            DownloadState.Completed => AppLocalizer.T("已完成", "Completed"),
            DownloadState.Failed => AppLocalizer.T("失败", "Failed"),
            DownloadState.Canceled => AppLocalizer.T("已取消", "Canceled"),
            _ => state.ToString()
        };
    }
}
