#include "pch.h"
#include "XamlApplication.h"
#include "Xaml.XamlApplication.g.cpp"

#include "winrt/Microsoft.UI.Xaml.XamlTypeInfo.h"

namespace winrt::Microsoft::ReactNative::Xaml::implementation {
using namespace ::winrt::Microsoft::UI::Xaml;
using namespace ::winrt::Microsoft::UI::Xaml::Markup;
using namespace ::winrt::Windows::UI::Xaml::Interop;
XamlApplication::XamlApplication() {
  s_current = *this;

  // TODO: It's probably not a good idea to only load the controls pri file, there are other ones too.
  auto resourceManager =
      winrt::Microsoft::Windows::ApplicationModel::Resources::ResourceManager(L"Microsoft.UI.Xaml.Controls.pri");

  this->ResourceManagerRequested([resourceManager](auto &&, ResourceManagerRequestedEventArgs args) {
    args.CustomResourceManager(resourceManager);
  });
  winrt::Microsoft::UI::Xaml::Hosting::WindowsXamlManager::InitializeForCurrentThread();

  m_providers.push_back(
      winrt::make_self<winrt::Microsoft::ReactNative::implementation::XamlMetaDataProvider>()
          .as<winrt::Microsoft::UI::Xaml::Markup::IXamlMetadataProvider>()); // Default generated provider
  m_providers.push_back(winrt::Microsoft::UI::Xaml::XamlTypeInfo::XamlControlsXamlMetaDataProvider());

  auto winUIResources = winrt::Microsoft::UI::Xaml::Controls::XamlControlsResources();
  Resources().MergedDictionaries().Append(winUIResources);
}

XamlApplication::~XamlApplication() {
  s_current = nullptr;
}

void XamlApplication::AddMetadataProvider(
    winrt::Microsoft::UI::Xaml::Markup::IXamlMetadataProvider const &otherProvider) {
  m_providers.push_back(otherProvider);
}

winrt::Microsoft::UI::Xaml::Markup::IXamlType XamlApplication::GetXamlType(
    winrt::Windows::UI::Xaml::Interop::TypeName const &type) {
  for (const auto &provider : m_providers) {
    if (auto result = provider.GetXamlType(type)) {
      return result;
    }
  }
  return nullptr;
}

winrt::Microsoft::UI::Xaml::Markup::IXamlType XamlApplication::GetXamlType(hstring const &fullName) {
  for (const auto &provider : m_providers) {
    if (auto result = provider.GetXamlType(fullName)) {
      return result;
    }
  }

  return nullptr;
}
com_array<winrt::Microsoft::UI::Xaml::Markup::XmlnsDefinition> XamlApplication::GetXmlnsDefinitions() {
  std::vector<::winrt::Microsoft::UI::Xaml::Markup::XmlnsDefinition> allDefinitions;
  for (const auto &provider : m_providers) {
    const auto &definitions = provider.GetXmlnsDefinitions();
    allDefinitions.insert(allDefinitions.cend(), definitions.cbegin(), definitions.cend());
  }
  return winrt::com_array<::winrt::Microsoft::UI::Xaml::Markup::XmlnsDefinition>(
      allDefinitions.begin(), allDefinitions.end());
}

winrt::Microsoft::ReactNative::Xaml::XamlApplication XamlApplication::s_current{nullptr};
} // namespace winrt::Microsoft::ReactNative::Xaml::implementation
