using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Logging;
using Microsoft.Web.WebView2.Core;

namespace ClawdDotNet.UI;

public sealed class WebViewBridge : IDisposable
{
    private static readonly JsonSerializerOptions JsonOpts = new()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
    };

    private readonly Microsoft.Web.WebView2.WinForms.WebView2 _wv;
    private readonly ILogger _logger;

    public event Action<BridgeMessage>? MessageReceived;

    public WebViewBridge(
        Microsoft.Web.WebView2.WinForms.WebView2 webView,
        ILogger logger)
    {
        _wv = webView;
        _logger = logger;
        _wv.CoreWebView2.WebMessageReceived += OnWebMessageReceived;
    }

    public async Task SendAsync(BridgeMessage message)
    {
        var json = JsonSerializer.Serialize(message, JsonOpts);
        var script = $"window.__bridge?.receive({json})";

        if (_wv.InvokeRequired)
        {
            await Task.Factory.FromAsync(
                _wv.BeginInvoke(new Func<Task>(async () =>
                    await _wv.CoreWebView2.ExecuteScriptAsync(script))),
                _ => { });
        }
        else
        {
            await _wv.CoreWebView2.ExecuteScriptAsync(script);
        }
    }

    private void OnWebMessageReceived(object? sender, CoreWebView2WebMessageReceivedEventArgs e)
    {
        try
        {
            var raw = e.TryGetWebMessageAsString();
            _logger.LogDebug("Bridge raw incoming: {Raw}", raw);

            if (string.IsNullOrWhiteSpace(raw)) return;

            var msg = JsonSerializer.Deserialize<BridgeMessage>(raw, JsonOpts);
            _logger.LogInformation("Bridge received: type={Type}, agentId={AgentId}, content={Content}",
                msg?.Type, msg?.AgentId, msg?.Content?.Length > 50 ? msg.Content[..50] + "..." : msg?.Content);

            if (msg is not null)
                MessageReceived?.Invoke(msg);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Bridge: failed to deserialize incoming message");
        }
    }

    public void Dispose()
    {
        if (_wv.CoreWebView2 is not null)
            _wv.CoreWebView2.WebMessageReceived -= OnWebMessageReceived;
    }
}
