using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Web.WebView2.Core;
using Windows.ApplicationModel.DataTransfer;
using Windows.Storage.Pickers;
using Windows.System;
using WinRT.Interop;
using YMhut.Box.Core.Settings;
using YMhut.Box.Core.Tools;

namespace YMhut.Box.WinUI.Services;

public sealed record ToolPageWebMessage(string Action, string? Value = null, JsonElement? Payload = null);

public sealed class ToolPageWebBridge(
    IToolResultExperienceCatalog experienceCatalog,
    ISettingsService settingsService,
    IToolLinkNavigationService linkNavigationService)
{
    private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web)
    {
        WriteIndented = false
    };

    static ToolPageWebBridge()
    {
        JsonOptions.Converters.Add(new JsonStringEnumConverter());
    }

    public ToolPageWebPayload CreatePayload(
        IToolModule module,
        ToolPageSpec spec,
        ToolInputState input,
        ToolResultDocument? result = null,
        ToolResultRunState? runState = null)
    {
        var experience = experienceCatalog.GetRequiredPage(module.Id);
        return new ToolPageWebPayload(
            module.Id,
            ToolText.Name(module),
            ToolText.Description(module),
            spec,
            experience,
            input,
            settingsService.Current.Theme,
            settingsService.Current.Language,
            new ToolResultPrivacyPolicy(ToolResultPrivacySanitizer.DefaultRedactedHostHints),
            new ToolPageRuntimeMetadata(
                DateTimeOffset.Now,
                spec.AutoRunOnOpen,
                module.Metadata.OfflineCapable,
                module.Metadata.Category.ToString(),
                module.Metadata.IconGlyph),
            experience.Actions,
            result,
            runState);
    }

    public string Serialize(ToolPageWebPayload payload)
        => JsonSerializer.Serialize(new { type = "toolPagePayload", payload }, JsonOptions);

    public string SerializeResult(ToolResultDocument document, ToolResultRunState runState, long durationMs)
        => JsonSerializer.Serialize(new { type = "toolResult", document, runState, durationMs }, JsonOptions);

    public string SerializeState(ToolResultRunState runState)
        => JsonSerializer.Serialize(new { type = "toolRunState", runState }, JsonOptions);

    public string SerializeTheme()
        => JsonSerializer.Serialize(new
        {
            type = "settingsChanged",
            theme = settingsService.Current.Theme,
            language = settingsService.Current.Language
        }, JsonOptions);

    public static ToolPageWebMessage ParseMessage(CoreWebView2WebMessageReceivedEventArgs args)
    {
        using var message = JsonDocument.Parse(args.WebMessageAsJson);
        var root = message.RootElement.Clone();
        var action = root.TryGetProperty("action", out var actionElement) ? actionElement.GetString() ?? string.Empty : string.Empty;
        var value = root.TryGetProperty("value", out var valueElement) ? valueElement.GetString() : null;
        var payload = root.TryGetProperty("payload", out var payloadElement) ? payloadElement.Clone() : (JsonElement?)null;
        return new ToolPageWebMessage(action, value, payload);
    }

    public async Task<string?> HandleSystemActionAsync(
        ToolPageWebMessage message,
        IToolModule module,
        string rawResult,
        IReadOnlyList<string> fileTypeFilters)
    {
        switch (message.Action)
        {
            case "copy":
                CopyText(ToolResultPrivacySanitizer.Redact(
                    message.Value ?? rawResult,
                    settingsService.Current.Language));
                ToastService.Show(AppLocalizer.T("已复制", "Copied"), ToastKind.Success);
                return null;
            case "openFile":
                if (!string.IsNullOrWhiteSpace(message.Value))
                {
                    await Launcher.LaunchFileAsync(await Windows.Storage.StorageFile.GetFileFromPathAsync(message.Value));
                }
                return null;
            case "openFolder":
                if (!string.IsNullOrWhiteSpace(message.Value))
                {
                    var folder = Directory.Exists(message.Value) ? message.Value : Path.GetDirectoryName(message.Value);
                    if (!string.IsNullOrWhiteSpace(folder))
                    {
                        await Launcher.LaunchFolderPathAsync(folder);
                    }
                }
                return null;
            case "openLink":
                await linkNavigationService.OpenAsync(message.Value);
                return null;
            case "openSystemBrowser":
                await linkNavigationService.OpenAsync(message.Value, ToolLinkTarget.SystemBrowser);
                return null;
            case "chooseFile":
                return await PickFileAsync(fileTypeFilters);
            case "copyResult":
                CopyText(ToolResultPrivacySanitizer.Redact(rawResult, settingsService.Current.Language));
                ToastService.Show(AppLocalizer.T("结果已复制", "Result copied"), ToastKind.Success);
                return null;
            default:
                return null;
        }
    }

    private static async Task<string?> PickFileAsync(IReadOnlyList<string> fileTypeFilters)
    {
        if (App.CurrentWindow is null)
        {
            return null;
        }

        var picker = new FileOpenPicker();
        InitializeWithWindow.Initialize(picker, WindowNative.GetWindowHandle(App.CurrentWindow));
        foreach (var extension in fileTypeFilters.Count == 0 ? ["*"] : fileTypeFilters)
        {
            picker.FileTypeFilter.Add(extension);
        }

        var file = await picker.PickSingleFileAsync();
        return file?.Path;
    }

    private static void CopyText(string text)
    {
        var data = new DataPackage();
        data.SetText(text);
        Clipboard.SetContent(data);
    }
}
