using System.Runtime.InteropServices;
using Microsoft.UI;
using Microsoft.UI.Text;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Automation;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Imaging;
using Windows.Graphics;
using Windows.UI.ViewManagement;
using WinRT.Interop;
using YMhut.Box.Core.Settings;
using YMhut.Box.WinUI.Services;

namespace YMhut.Box.WinUI;

public sealed class AgreementWindow : Window
{
    private const double DesiredWindowWidthDip = 760;
    private const double DesiredWindowHeightDip = 640;

    private readonly ISettingsService _settingsService;
    private readonly IAgreementAcceptanceStore _acceptanceStore;
    private readonly string _appVersion;
    private readonly Func<Task> _accepted;
    private readonly ElementTheme _requestedTheme;
    private Button _acceptButton = null!;
    private bool _acceptedAndContinuing;

    public AgreementWindow(
        ISettingsService settingsService,
        IAgreementAcceptanceStore acceptanceStore,
        string appVersion,
        Func<Task> accepted)
    {
        _settingsService = settingsService;
        _acceptanceStore = acceptanceStore;
        _appVersion = appVersion;
        _accepted = accepted;
        _requestedTheme = ResolveElementTheme(settingsService.Current.Theme);
        Title = $"YMhut Box 使用声明 · {AgreementDocument.CurrentVersion}";
        WindowIconService.ApplyAppIcon(this);
        ModernUi.SetPalette(ShouldUseDarkPalette(settingsService.Current.Theme));
        ThemeService.ApplyFontScale(settingsService.Current.FontSize);
        Content = BuildContent();
        ApplyWindowTheme();
        Closed += AgreementWindow_Closed;
        ResizeWindow();
    }

    private UIElement BuildContent()
    {
        var agreeCheck = new CheckBox
        {
            Content = AppLocalizer.T("我已阅读并同意以上声明", "I have read and agree to this statement"),
            FontSize = 14,
            Foreground = ThemeBrush("TextFillColorPrimaryBrush", ModernUi.TextPrimary),
            MinHeight = 34,
            Padding = new Thickness(2, 0, 0, 0),
            VerticalAlignment = VerticalAlignment.Center
        };
        AutomationProperties.SetName(agreeCheck, AppLocalizer.T("同意使用声明", "Accept agreement statement"));

        _acceptButton = CreateActionButton(AppLocalizer.T("同意并进入", "Agree and continue"), "\uE73E", primary: true);
        SetAcceptButtonState(false);
        _acceptButton.Click += async (_, _) => await AcceptAsync();

        var decline = CreateActionButton(AppLocalizer.T("拒绝并退出", "Decline and exit"), "\uE711", primary: false);
        decline.Click += (_, _) => Application.Current.Exit();

        agreeCheck.Checked += (_, _) => SetAcceptButtonState(true);
        agreeCheck.Unchecked += (_, _) => SetAcceptButtonState(false);

        var statement = ModernUi.Text(AgreementText(), 14, foreground: ThemeBrush("TextFillColorSecondaryBrush", ModernUi.TextSecondary));
        statement.LineHeight = 23;
        statement.TextWrapping = TextWrapping.WrapWholeWords;
        statement.TextTrimming = TextTrimming.None;
        statement.HorizontalAlignment = HorizontalAlignment.Stretch;

        var statementCard = ModernUi.Card(
            statement,
            new Thickness(16),
            radius: 8,
            background: ThemeBrush("CardBackgroundFillColorDefaultBrush", ModernUi.Surface));
        statementCard.HorizontalAlignment = HorizontalAlignment.Stretch;

        var scrollContent = new StackPanel
        {
            Spacing = 16,
            HorizontalAlignment = HorizontalAlignment.Stretch,
            Children =
            {
                BuildHeader(),
                statementCard
            }
        };

        var bodyScroll = new ScrollViewer
        {
            VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
            VerticalScrollMode = ScrollMode.Enabled,
            HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled,
            HorizontalScrollMode = ScrollMode.Disabled,
            Content = scrollContent
        };
        bodyScroll.SizeChanged += (_, args) =>
        {
            var width = Math.Max(0, args.NewSize.Width);
            scrollContent.Width = width;
            statementCard.Width = width;
            statement.Width = Math.Max(280, width - 48);
        };

        var footer = ModernUi.Card(
            BuildFooter(agreeCheck, decline, _acceptButton),
            new Thickness(16, 12, 16, 14),
            radius: 8,
            background: ThemeBrush("CardBackgroundFillColorDefaultBrush", ModernUi.Surface));
        footer.VerticalAlignment = VerticalAlignment.Bottom;

        var root = new Grid
        {
            Background = ThemeBrush("ApplicationPageBackgroundThemeBrush", ModernUi.AppBackground),
            Padding = new Thickness(24),
            RowSpacing = 14,
            RowDefinitions =
            {
                new RowDefinition { Height = new GridLength(1, GridUnitType.Star) },
                new RowDefinition { Height = GridLength.Auto }
            }
        };

        root.Children.Add(bodyScroll);
        Grid.SetRow(footer, 1);
        root.Children.Add(footer);
        return root;
    }

    private static Grid BuildFooter(CheckBox agreeCheck, Button decline, Button acceptButton)
    {
        var footer = new Grid
        {
            RowSpacing = 12,
            RowDefinitions =
            {
                new RowDefinition { Height = GridLength.Auto },
                new RowDefinition { Height = GridLength.Auto }
            }
        };
        footer.Children.Add(agreeCheck);

        var commandRow = new Grid
        {
            ColumnSpacing = 10,
            ColumnDefinitions =
            {
                new ColumnDefinition(),
                new ColumnDefinition { Width = GridLength.Auto },
                new ColumnDefinition { Width = GridLength.Auto }
            }
        };

        Grid.SetColumn(decline, 1);
        Grid.SetColumn(acceptButton, 2);
        commandRow.Children.Add(new Border());
        commandRow.Children.Add(decline);
        commandRow.Children.Add(acceptButton);

        Grid.SetRow(commandRow, 1);
        footer.Children.Add(commandRow);
        return footer;
    }

    private Button CreateActionButton(string text, string glyph, bool primary)
    {
        var secondaryForeground = ThemeBrush("TextFillColorPrimaryBrush", ModernUi.TextPrimary);
        var foreground = primary ? ModernUi.Brush("#FFFFFFFF") : secondaryForeground;
        var buttonText = ModernUi.Text(text, 14, FontWeights.SemiBold, foreground, maxLines: 1);
        buttonText.TextWrapping = TextWrapping.NoWrap;

        var icon = new FontIcon
        {
            Glyph = glyph,
            FontSize = 15,
            Foreground = foreground,
            VerticalAlignment = VerticalAlignment.Center
        };

        var content = new StackPanel
        {
            Orientation = Orientation.Horizontal,
            Spacing = 8,
            HorizontalAlignment = HorizontalAlignment.Center,
            VerticalAlignment = VerticalAlignment.Center,
            Children = { icon, buttonText }
        };

        var button = new Button
        {
            MinWidth = primary ? 138 : 124,
            MinHeight = 38,
            Padding = new Thickness(14, 8, 14, 8),
            CornerRadius = new CornerRadius(6),
            Background = primary ? ThemeBrush("AccentFillColorDefaultBrush", ModernUi.Accent) : ThemeBrush("ControlFillColorDefaultBrush", ModernUi.SurfaceAlt),
            Foreground = foreground,
            BorderBrush = primary ? ThemeBrush("AccentFillColorDefaultBrush", ModernUi.Accent) : ThemeBrush("ControlStrokeColorDefaultBrush", ModernUi.Stroke),
            BorderThickness = new Thickness(1),
            Content = content
        };
        AutomationProperties.SetName(button, text);
        return button;
    }

    private void SetAcceptButtonState(bool enabled)
    {
        if (_acceptButton is null)
        {
            return;
        }

        var foreground = enabled ? ModernUi.Brush("#FFFFFFFF") : ThemeBrush("TextFillColorSecondaryBrush", ModernUi.TextSecondary);
        _acceptButton.IsEnabled = enabled;
        _acceptButton.Background = enabled ? ThemeBrush("AccentFillColorDefaultBrush", ModernUi.Accent) : ThemeBrush("ControlFillColorDefaultBrush", ModernUi.SurfaceAlt);
        _acceptButton.Foreground = foreground;
        _acceptButton.BorderBrush = enabled ? ThemeBrush("AccentFillColorDefaultBrush", ModernUi.Accent) : ThemeBrush("ControlStrokeColorDefaultBrush", ModernUi.Stroke);
        SetButtonContentForeground(_acceptButton, foreground);
    }

    private static void SetButtonContentForeground(Button button, Brush foreground)
    {
        if (button.Content is not Panel panel)
        {
            return;
        }

        foreach (var child in panel.Children)
        {
            switch (child)
            {
                case FontIcon icon:
                    icon.Foreground = foreground;
                    break;
                case TextBlock text:
                    text.Foreground = foreground;
                    break;
            }
        }
    }

    private UIElement BuildHeader()
    {
        var grid = new Grid { ColumnSpacing = 14 };
        grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
        grid.ColumnDefinitions.Add(new ColumnDefinition());
        grid.Children.Add(new Border
        {
            Width = 58,
            Height = 58,
            CornerRadius = new CornerRadius(8),
            Background = ThemeBrush("AccentFillColorTertiaryBrush", ModernUi.AccentSoft),
            BorderBrush = ThemeBrush("CardStrokeColorDefaultBrush", ModernUi.Stroke),
            BorderThickness = new Thickness(1),
            Child = new Image
            {
                Source = new BitmapImage(new Uri("ms-appx:///Assets/icons/app_icon.png")),
                Width = 34,
                Height = 34,
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center
            }
        });

        var title = new StackPanel
        {
            Spacing = 4,
            VerticalAlignment = VerticalAlignment.Center,
            Children =
            {
                ModernUi.Text($"YMhut Box 使用声明 · {AgreementDocument.CurrentVersion}", 24, FontWeights.SemiBold, ThemeBrush("TextFillColorPrimaryBrush", ModernUi.TextPrimary), maxLines: 1),
                ModernUi.Text(AppLocalizer.T("请确认你理解 YMhut Box 的使用边界、免责条款与风险提示。", "Please confirm that you understand YMhut Box usage boundaries, disclaimers, and safety notes."), 14, foreground: ThemeBrush("TextFillColorSecondaryBrush", ModernUi.TextSecondary), maxLines: 2)
            }
        };
        Grid.SetColumn(title, 1);
        grid.Children.Add(title);
        return grid;
    }

    private void ApplyWindowTheme()
    {
        ModernUi.SetPalette(ShouldUseDarkPalette(_settingsService.Current.Theme));

        if (Content is FrameworkElement root)
        {
            root.RequestedTheme = _requestedTheme;
        }

        ThemeService.ApplyWindowBackdrop(this, _settingsService.Current.WindowBackdrop);
    }

    private async Task AcceptAsync()
    {
        _acceptButton.IsEnabled = false;
        var acceptedAt = DateTimeOffset.Now;

        try
        {
            await _acceptanceStore.RecordAcceptedAsync(
                AgreementDocument.CurrentVersion,
                AgreementDocument.CurrentRevision,
                _appVersion,
                AppLocalizer.CurrentLanguage,
                acceptedAt);
        }
        catch (Exception exception)
        {
            CrashLog.Write(exception);
        }

        await _settingsService.UpdateAsync(settings =>
        {
            settings.UserAgreementAccepted = true;
            settings.UserAgreementVersion = AgreementDocument.CurrentVersion;
            settings.UserAgreementAcceptedAt = acceptedAt;
        });
        _acceptedAndContinuing = true;
        await _accepted();
        Close();
    }

    private void AgreementWindow_Closed(object sender, WindowEventArgs args)
    {
        if (!_acceptedAndContinuing)
        {
            Application.Current.Exit();
        }
    }

    private void ResizeWindow()
    {
        try
        {
            var hwnd = WindowNative.GetWindowHandle(this);
            var windowId = Win32Interop.GetWindowIdFromWindow(hwnd);
            var appWindow = AppWindow.GetFromWindowId(windowId);
            var scale = GetWindowScale(hwnd);
            var width = DipToPixels(DesiredWindowWidthDip, scale);
            var height = DipToPixels(DesiredWindowHeightDip, scale);

            var displayArea = DisplayArea.GetFromWindowId(windowId, DisplayAreaFallback.Nearest);
            if (displayArea is not null)
            {
                var workArea = displayArea.WorkArea;
                width = Math.Min(width, Math.Max(DipToPixels(480, scale), workArea.Width - DipToPixels(48, scale)));
                height = Math.Min(height, Math.Max(DipToPixels(420, scale), workArea.Height - DipToPixels(48, scale)));
                appWindow.Resize(new SizeInt32(width, height));
                appWindow.Move(new PointInt32(
                    workArea.X + Math.Max(0, (workArea.Width - width) / 2),
                    workArea.Y + Math.Max(0, (workArea.Height - height) / 2)));
                return;
            }

            appWindow.Resize(new SizeInt32(width, height));
        }
        catch
        {
        }
    }

    private static double GetWindowScale(IntPtr hwnd)
    {
        try
        {
            var dpi = GetDpiForWindow(hwnd);
            return dpi > 0 ? dpi / 96.0 : 1.0;
        }
        catch
        {
            return 1.0;
        }
    }

    private static int DipToPixels(double dips, double scale)
    {
        return Math.Max(1, (int)Math.Round(dips * scale));
    }

    private Brush ThemeBrush(string resourceKey, Brush fallback)
    {
        return Application.Current.Resources.TryGetValue(resourceKey, out var value) && value is Brush brush
            ? brush
            : fallback;
    }

    private static ElementTheme ResolveElementTheme(string? theme)
    {
        return (theme ?? string.Empty).Trim().ToLowerInvariant() switch
        {
            "light" => ElementTheme.Light,
            "dark" => ElementTheme.Dark,
            _ => ElementTheme.Default
        };
    }

    private static bool ShouldUseDarkPalette(string? theme)
    {
        return (theme ?? string.Empty).Trim().ToLowerInvariant() switch
        {
            "light" => false,
            "dark" => true,
            _ => IsSystemDarkTheme()
        };
    }

    private static bool IsSystemDarkTheme()
    {
        try
        {
            var background = new UISettings().GetColorValue(UIColorType.Background);
            var luminance = (0.2126 * background.R) + (0.7152 * background.G) + (0.0722 * background.B);
            return luminance < 128;
        }
        catch
        {
            return false;
        }
    }

    [DllImport("user32.dll")]
    private static extern uint GetDpiForWindow(IntPtr hwnd);

    private static string AgreementText()
    {
        return AppLocalizer.T(
            """
            YMhut Box 是面向个人效率、系统诊断和工具集合的桌面应用。部分工具可能访问网络、读取本机状态、启动外部程序、修改系统相关配置，或处理你主动提供的文件。请在确认来源可信、重要数据已备份、操作风险可接受的前提下使用。

            免责与风险提示：
            1. 工具输出仅供参考，你需要自行判断输出、建议、排行榜、第三方数据和检测结果的准确性、完整性与适用性。
            2. 涉及系统设置、注册表、证书、Hosts、Defender、防火墙、清理删除、管理员运行、脚本执行或未知可执行文件启动的操作，可能影响系统稳定性和数据安全。
            3. 网络请求、第三方接口、价格/指标数据、媒体资源和资讯内容可能变化、延迟、失效或被第三方限制；YMhut Box 不保证其持续可用。
            4. 文件处理、图片/音视频加载、压缩解压、格式转换、批量操作和外部工具调用可能产生不可逆结果，请自行保留原始文件备份。
            5. 更新安装和覆盖安装会替换程序文件并清理旧版程序残留，但会尽力保留用户设置、日志、下载队列、插件状态等用户数据。
            6. 插件和外部程序由其各自作者负责。启用插件、加载外部工具或执行第三方程序前，请确认其来源与权限需求。
            7. 应用会在本机保存必要的设置、日志、自检结果和轻量运行状态，用于恢复界面、诊断问题和改进体验；不会把 runtime、Tools、Metadata 或完整安装布局持久复制到用户数据目录。
            8. 继续使用表示你已阅读并理解上述声明，并愿意对自己的操作、数据备份和使用结果承担责任。
            """,
            """
            YMhut Box is a desktop app for personal productivity, diagnostics, and utility workflows. Some tools may access the network, read local system state, launch external programs, modify system-related settings, or process files you provide. Use them only when the source is trusted, important data is backed up, and the operation risk is acceptable.

            Disclaimer and safety notes:
            1. Tool output is for reference only. You are responsible for judging the accuracy, completeness, and applicability of output, suggestions, rankings, third-party data, and diagnostics.
            2. Operations involving system settings, registry, certificates, Hosts, Defender, firewall, cleanup/deletion, administrator execution, scripts, or unknown executables may affect system stability and data safety.
            3. Network requests, third-party APIs, price/metric data, media resources, and news content may change, be delayed, expire, or be limited by third parties. YMhut Box does not guarantee continuous availability.
            4. File processing, image/audio/video loading, archive operations, format conversion, batch operations, and external tool calls may produce irreversible results. Keep original backups.
            5. Updates and overwrite installs replace application files and clean old application remnants while preserving user settings, logs, download queues, and plugin state where possible.
            6. Plugins and external programs are maintained by their own authors. Confirm source and permission needs before enabling plugins or launching external tools.
            7. The app stores necessary local settings, logs, startup check results, and lightweight runtime state for UI restore and diagnostics. It does not persist runtime, Tools, Metadata, or a full installation payload in the user data folder.
            8. Continuing means you have read and understood this statement and accept responsibility for your operations, backups, and usage results.
            """);
    }
}
