//
// EdgeHTML browser engine
//

// EdgeHTML headers and libs
#include <objbase.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Web.UI.Interop.h>
#pragma comment(lib, "windowsapp")

using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Web::UI;
using namespace Windows::Web::UI::Interop;

class edge_html : public browser
{
public:
  bool embed(HWND wnd, bool debug, msg_cb_t cb) override
  {
    init_apartment(winrt::apartment_type::single_threaded);
    auto process = WebViewControlProcess();
    auto op = process.CreateWebViewControlAsync(reinterpret_cast<int64_t>(wnd),
                                                Rect());
    if (op.Status() != AsyncStatus::Completed)
    {
      handle h(CreateEvent(nullptr, false, false, nullptr));
      op.Completed([h = h.get()](auto, auto)
                   { SetEvent(h); });
      HANDLE hs[] = {h.get()};
      DWORD i;
      CoWaitForMultipleHandles(COWAIT_DISPATCH_WINDOW_MESSAGES |
                                   COWAIT_DISPATCH_CALLS |
                                   COWAIT_INPUTAVAILABLE,
                               INFINITE, 1, hs, &i);
    }
    m_webview = op.GetResults();
    m_webview.Settings().IsScriptNotifyAllowed(true);
    m_webview.IsVisible(true);
    m_webview.ScriptNotify([=](auto const &sender, auto const &args)
                           {
                             std::string s = winrt::to_string(args.Value());
                             cb(s.c_str());
                           });
    m_webview.NavigationStarting([=](auto const &sender, auto const &args)
                                 { m_webview.AddInitializeScript(winrt::to_hstring(init_js)); });
    init("window.external.invoke = s => window.external.notify(s)");
    return true;
  } //

  void navigate(const std::string url) override
  {
    std::string html = html_from_uri(url);
    if (html != "")
    {
      m_webview.NavigateToString(winrt::to_hstring(html));
    }
    else
    {
      Uri uri(winrt::to_hstring(url));
      m_webview.Navigate(uri);
    }
  } //

  void init(const std::string js) override
  {
    init_js = init_js + "(function(){" + js + "})();";
  } //

  void eval(const std::string js) override
  {
    m_webview.InvokeScriptAsync(
        L"eval", single_threaded_vector<hstring>({winrt::to_hstring(js)}));
  } //

  void resize(HWND wnd) override
  {
    if (m_webview == nullptr)
    {
      return;
    }
    RECT r;
    GetClientRect(wnd, &r);
    Rect bounds(r.left, r.top, r.right - r.left, r.bottom - r.top);
    m_webview.Bounds(bounds);
  } //

private:
  WebViewControl m_webview = nullptr;
  std::string init_js = "";
};