///
/// HybridVideoViewComponent.cpp
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
/// https://github.com/mrousavy/nitro
/// Copyright © Marc Rousavy @ Margelo
///

#include "HybridVideoViewComponent.hpp"

#include <string>
#include <exception>
#include <utility>
#include <NitroModules/NitroDefines.hpp>
#include <NitroModules/JSIConverter.hpp>
#include <NitroModules/PropNameIDCache.hpp>
#include <react/renderer/core/RawValue.h>
#include <react/renderer/core/ShadowNode.h>
#include <react/renderer/core/ComponentDescriptor.h>
#include <react/renderer/components/view/ViewProps.h>

namespace margelo::nitro::aviation::views {

  extern const char HybridVideoViewComponentName[] = "VideoView";

  HybridVideoViewProps::HybridVideoViewProps(const react::PropsParserContext& context,
                                             const HybridVideoViewProps& sourceProps,
                                             const react::RawProps& rawProps):
    react::ViewProps(context, sourceProps, rawProps, filterObjectKeys),
    resizeMode([&]() -> CachedProp<ResizeMode> {
      try {
        const react::RawValue* rawValue = rawProps.at("resizeMode", nullptr, nullptr);
        if (rawValue == nullptr) return sourceProps.resizeMode;
        const auto& [runtime, value] = (std::pair<jsi::Runtime*, jsi::Value>)*rawValue;
        return CachedProp<ResizeMode>::fromRawValue(*runtime, value, sourceProps.resizeMode);
      } catch (const std::exception& exc) {
        throw std::runtime_error(std::string("VideoView.resizeMode: ") + exc.what());
      }
    }()),
    pipEnabled([&]() -> CachedProp<bool> {
      try {
        const react::RawValue* rawValue = rawProps.at("pipEnabled", nullptr, nullptr);
        if (rawValue == nullptr) return sourceProps.pipEnabled;
        const auto& [runtime, value] = (std::pair<jsi::Runtime*, jsi::Value>)*rawValue;
        return CachedProp<bool>::fromRawValue(*runtime, value, sourceProps.pipEnabled);
      } catch (const std::exception& exc) {
        throw std::runtime_error(std::string("VideoView.pipEnabled: ") + exc.what());
      }
    }()),
    playInBackground([&]() -> CachedProp<bool> {
      try {
        const react::RawValue* rawValue = rawProps.at("playInBackground", nullptr, nullptr);
        if (rawValue == nullptr) return sourceProps.playInBackground;
        const auto& [runtime, value] = (std::pair<jsi::Runtime*, jsi::Value>)*rawValue;
        return CachedProp<bool>::fromRawValue(*runtime, value, sourceProps.playInBackground);
      } catch (const std::exception& exc) {
        throw std::runtime_error(std::string("VideoView.playInBackground: ") + exc.what());
      }
    }()),
    onPipStart([&]() -> CachedProp<std::function<void()>> {
      try {
        const react::RawValue* rawValue = rawProps.at("onPipStart", nullptr, nullptr);
        if (rawValue == nullptr) return sourceProps.onPipStart;
        const auto& [runtime, value] = (std::pair<jsi::Runtime*, jsi::Value>)*rawValue;
        return CachedProp<std::function<void()>>::fromRawValue(*runtime, value.asObject(*runtime).getProperty(*runtime, PropNameIDCache::get(*runtime, "f")), sourceProps.onPipStart);
      } catch (const std::exception& exc) {
        throw std::runtime_error(std::string("VideoView.onPipStart: ") + exc.what());
      }
    }()),
    onPipStop([&]() -> CachedProp<std::function<void()>> {
      try {
        const react::RawValue* rawValue = rawProps.at("onPipStop", nullptr, nullptr);
        if (rawValue == nullptr) return sourceProps.onPipStop;
        const auto& [runtime, value] = (std::pair<jsi::Runtime*, jsi::Value>)*rawValue;
        return CachedProp<std::function<void()>>::fromRawValue(*runtime, value.asObject(*runtime).getProperty(*runtime, PropNameIDCache::get(*runtime, "f")), sourceProps.onPipStop);
      } catch (const std::exception& exc) {
        throw std::runtime_error(std::string("VideoView.onPipStop: ") + exc.what());
      }
    }()),
    surfaceType([&]() -> CachedProp<SurfaceType> {
      try {
        const react::RawValue* rawValue = rawProps.at("surfaceType", nullptr, nullptr);
        if (rawValue == nullptr) return sourceProps.surfaceType;
        const auto& [runtime, value] = (std::pair<jsi::Runtime*, jsi::Value>)*rawValue;
        return CachedProp<SurfaceType>::fromRawValue(*runtime, value, sourceProps.surfaceType);
      } catch (const std::exception& exc) {
        throw std::runtime_error(std::string("VideoView.surfaceType: ") + exc.what());
      }
    }()),
    onFullscreenEnter([&]() -> CachedProp<std::function<void()>> {
      try {
        const react::RawValue* rawValue = rawProps.at("onFullscreenEnter", nullptr, nullptr);
        if (rawValue == nullptr) return sourceProps.onFullscreenEnter;
        const auto& [runtime, value] = (std::pair<jsi::Runtime*, jsi::Value>)*rawValue;
        return CachedProp<std::function<void()>>::fromRawValue(*runtime, value.asObject(*runtime).getProperty(*runtime, PropNameIDCache::get(*runtime, "f")), sourceProps.onFullscreenEnter);
      } catch (const std::exception& exc) {
        throw std::runtime_error(std::string("VideoView.onFullscreenEnter: ") + exc.what());
      }
    }()),
    onFullscreenExit([&]() -> CachedProp<std::function<void()>> {
      try {
        const react::RawValue* rawValue = rawProps.at("onFullscreenExit", nullptr, nullptr);
        if (rawValue == nullptr) return sourceProps.onFullscreenExit;
        const auto& [runtime, value] = (std::pair<jsi::Runtime*, jsi::Value>)*rawValue;
        return CachedProp<std::function<void()>>::fromRawValue(*runtime, value.asObject(*runtime).getProperty(*runtime, PropNameIDCache::get(*runtime, "f")), sourceProps.onFullscreenExit);
      } catch (const std::exception& exc) {
        throw std::runtime_error(std::string("VideoView.onFullscreenExit: ") + exc.what());
      }
    }()),
    selectedVideoTrack([&]() -> CachedProp<VideoTrackSelection> {
      try {
        const react::RawValue* rawValue = rawProps.at("selectedVideoTrack", nullptr, nullptr);
        if (rawValue == nullptr) return sourceProps.selectedVideoTrack;
        const auto& [runtime, value] = (std::pair<jsi::Runtime*, jsi::Value>)*rawValue;
        return CachedProp<VideoTrackSelection>::fromRawValue(*runtime, value, sourceProps.selectedVideoTrack);
      } catch (const std::exception& exc) {
        throw std::runtime_error(std::string("VideoView.selectedVideoTrack: ") + exc.what());
      }
    }()),
    selectedSubtitleTrack([&]() -> CachedProp<SubtitleTrackSelection> {
      try {
        const react::RawValue* rawValue = rawProps.at("selectedSubtitleTrack", nullptr, nullptr);
        if (rawValue == nullptr) return sourceProps.selectedSubtitleTrack;
        const auto& [runtime, value] = (std::pair<jsi::Runtime*, jsi::Value>)*rawValue;
        return CachedProp<SubtitleTrackSelection>::fromRawValue(*runtime, value, sourceProps.selectedSubtitleTrack);
      } catch (const std::exception& exc) {
        throw std::runtime_error(std::string("VideoView.selectedSubtitleTrack: ") + exc.what());
      }
    }()),
    selectedAudioTrack([&]() -> CachedProp<AudioTrackSelection> {
      try {
        const react::RawValue* rawValue = rawProps.at("selectedAudioTrack", nullptr, nullptr);
        if (rawValue == nullptr) return sourceProps.selectedAudioTrack;
        const auto& [runtime, value] = (std::pair<jsi::Runtime*, jsi::Value>)*rawValue;
        return CachedProp<AudioTrackSelection>::fromRawValue(*runtime, value, sourceProps.selectedAudioTrack);
      } catch (const std::exception& exc) {
        throw std::runtime_error(std::string("VideoView.selectedAudioTrack: ") + exc.what());
      }
    }()),
    adTagUrl([&]() -> CachedProp<std::string> {
      try {
        const react::RawValue* rawValue = rawProps.at("adTagUrl", nullptr, nullptr);
        if (rawValue == nullptr) return sourceProps.adTagUrl;
        const auto& [runtime, value] = (std::pair<jsi::Runtime*, jsi::Value>)*rawValue;
        return CachedProp<std::string>::fromRawValue(*runtime, value, sourceProps.adTagUrl);
      } catch (const std::exception& exc) {
        throw std::runtime_error(std::string("VideoView.adTagUrl: ") + exc.what());
      }
    }()),
    source([&]() -> CachedProp<VideoSource> {
      try {
        const react::RawValue* rawValue = rawProps.at("source", nullptr, nullptr);
        if (rawValue == nullptr) return sourceProps.source;
        const auto& [runtime, value] = (std::pair<jsi::Runtime*, jsi::Value>)*rawValue;
        return CachedProp<VideoSource>::fromRawValue(*runtime, value, sourceProps.source);
      } catch (const std::exception& exc) {
        throw std::runtime_error(std::string("VideoView.source: ") + exc.what());
      }
    }()),
    autoPlay([&]() -> CachedProp<bool> {
      try {
        const react::RawValue* rawValue = rawProps.at("autoPlay", nullptr, nullptr);
        if (rawValue == nullptr) return sourceProps.autoPlay;
        const auto& [runtime, value] = (std::pair<jsi::Runtime*, jsi::Value>)*rawValue;
        return CachedProp<bool>::fromRawValue(*runtime, value, sourceProps.autoPlay);
      } catch (const std::exception& exc) {
        throw std::runtime_error(std::string("VideoView.autoPlay: ") + exc.what());
      }
    }()),
    hybridRef([&]() -> CachedProp<std::optional<std::function<void(const std::shared_ptr<HybridVideoViewSpec>& /* ref */)>>> {
      try {
        const react::RawValue* rawValue = rawProps.at("hybridRef", nullptr, nullptr);
        if (rawValue == nullptr) return sourceProps.hybridRef;
        const auto& [runtime, value] = (std::pair<jsi::Runtime*, jsi::Value>)*rawValue;
        return CachedProp<std::optional<std::function<void(const std::shared_ptr<HybridVideoViewSpec>& /* ref */)>>>::fromRawValue(*runtime, value.asObject(*runtime).getProperty(*runtime, PropNameIDCache::get(*runtime, "f")), sourceProps.hybridRef);
      } catch (const std::exception& exc) {
        throw std::runtime_error(std::string("VideoView.hybridRef: ") + exc.what());
      }
    }()) { }

  bool HybridVideoViewProps::filterObjectKeys(const std::string& propName) {
    switch (hashString(propName)) {
      case hashString("resizeMode"): return true;
      case hashString("pipEnabled"): return true;
      case hashString("playInBackground"): return true;
      case hashString("onPipStart"): return true;
      case hashString("onPipStop"): return true;
      case hashString("surfaceType"): return true;
      case hashString("onFullscreenEnter"): return true;
      case hashString("onFullscreenExit"): return true;
      case hashString("selectedVideoTrack"): return true;
      case hashString("selectedSubtitleTrack"): return true;
      case hashString("selectedAudioTrack"): return true;
      case hashString("adTagUrl"): return true;
      case hashString("source"): return true;
      case hashString("autoPlay"): return true;
      case hashString("hybridRef"): return true;
      default: return false;
    }
  }

  HybridVideoViewComponentDescriptor::HybridVideoViewComponentDescriptor(const react::ComponentDescriptorParameters& parameters)
    : ConcreteComponentDescriptor(parameters,
                                  react::RawPropsParser(/* enableJsiParser */ true)) {}

  std::shared_ptr<const react::Props> HybridVideoViewComponentDescriptor::cloneProps(const react::PropsParserContext& context,
                                                                                     const std::shared_ptr<const react::Props>& props,
                                                                                     react::RawProps rawProps) const {
    // 1. Prepare raw props parser
    rawProps.parse(rawPropsParser_);
    // 2. Copy props with Nitro's cached copy constructor
    return HybridVideoViewShadowNode::Props(context, /* & */ rawProps, props);
  }

#ifdef ANDROID
  void HybridVideoViewComponentDescriptor::adopt(react::ShadowNode& shadowNode) const {
    // This is called immediately after `ShadowNode` is created, cloned or in progress.
    // On Android, we need to wrap props in our state, which gets routed through Java and later unwrapped in JNI/C++.
    auto& concreteShadowNode = static_cast<HybridVideoViewShadowNode&>(shadowNode);
    const std::shared_ptr<const HybridVideoViewProps>& constProps = concreteShadowNode.getConcreteSharedProps();
    const std::shared_ptr<HybridVideoViewProps>& props = std::const_pointer_cast<HybridVideoViewProps>(constProps);
    HybridVideoViewState state{props};
    concreteShadowNode.setStateData(std::move(state));
  }
#endif

} // namespace margelo::nitro::aviation::views
