// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#pragma once

#include <memory>

#include "impeller/renderer/context.h"
#include "impeller/renderer/pipeline.h"
#include "impeller/renderer/pipeline_descriptor.h"
#include "impeller/scene/pipeline_key.h"

namespace impeller {
namespace scene {

struct SceneContextOptions {
  SampleCount sample_count = SampleCount::kCount1;
  PrimitiveType primitive_type = PrimitiveType::kTriangle;

  struct Hash {
    constexpr std::size_t operator()(const SceneContextOptions& o) const {
      return fml::HashCombine(o.sample_count, o.primitive_type);
    }
  };

  struct Equal {
    constexpr bool operator()(const SceneContextOptions& lhs,
                              const SceneContextOptions& rhs) const {
      return lhs.sample_count == rhs.sample_count &&
             lhs.primitive_type == rhs.primitive_type;
    }
  };

  void ApplyToPipelineDescriptor(const Capabilities& capabilities,
                                 PipelineDescriptor& desc) const;
};

class SceneContext {
 public:
  explicit SceneContext(std::shared_ptr<Context> context);

  ~SceneContext();

  bool IsValid() const;

  std::shared_ptr<Pipeline<PipelineDescriptor>> GetPipeline(
      PipelineKey key,
      SceneContextOptions opts) const;

  std::shared_ptr<Context> GetContext() const;

  std::shared_ptr<Texture> GetPlaceholderTexture() const;

 private:
  class PipelineVariants {
   public:
    virtual ~PipelineVariants() = default;

    virtual std::shared_ptr<Pipeline<PipelineDescriptor>> GetPipeline(
        Context& context,
        SceneContextOptions opts) = 0;
  };

  template <class PipelineT>
  class PipelineVariantsT final : public PipelineVariants {
   public:
    explicit PipelineVariantsT(Context& context) {
      auto desc = PipelineT::Builder::MakeDefaultPipelineDescriptor(context);
      if (!desc.has_value()) {
        is_valid_ = false;
        return;
      }
      // Apply default ContentContextOptions to the descriptor.
      SceneContextOptions{}.ApplyToPipelineDescriptor(
          /*capabilities=*/*context.GetCapabilities(),
          /*desc=*/desc.value());
      variants_[{}] = std::make_unique<PipelineT>(context, desc);
    };

    // |PipelineVariants|
    std::shared_ptr<Pipeline<PipelineDescriptor>> GetPipeline(
        Context& context,
        SceneContextOptions opts) {
      if (auto found = variants_.find(opts); found != variants_.end()) {
        return found->second->WaitAndGet();
      }

      auto prototype = variants_.find({});

      // The prototype must always be initialized in the constructor.
      FML_CHECK(prototype != variants_.end());

      auto variant_future = prototype->second->WaitAndGet()->CreateVariant(
          [&context, &opts,
           variants_count = variants_.size()](PipelineDescriptor& desc) {
            opts.ApplyToPipelineDescriptor(*context.GetCapabilities(), desc);
            desc.SetLabel(
                SPrintF("%s V#%zu", desc.GetLabel().c_str(), variants_count));
          });
      auto variant = std::make_unique<PipelineT>(std::move(variant_future));
      auto variant_pipeline = variant->WaitAndGet();
      variants_[opts] = std::move(variant);
      return variant_pipeline;
    }

    bool IsValid() const { return is_valid_; }

   private:
    bool is_valid_ = true;
    std::unordered_map<SceneContextOptions,
                       std::unique_ptr<PipelineT>,
                       SceneContextOptions::Hash,
                       SceneContextOptions::Equal>
        variants_;
  };

  template <typename VertexShader, typename FragmentShader>
  /// Creates a PipelineVariantsT for the given vertex and fragment shaders.
  ///
  /// If a pipeline could not be created, returns nullptr.
  std::unique_ptr<PipelineVariants> MakePipelineVariants(Context& context) {
    auto pipeline =
        PipelineVariantsT<RenderPipelineT<VertexShader, FragmentShader>>(
            context);
    if (!pipeline.IsValid()) {
      return nullptr;
    }
    return std::make_unique<
        PipelineVariantsT<RenderPipelineT<VertexShader, FragmentShader>>>(
        std::move(pipeline));
  }

  std::unordered_map<PipelineKey,
                     std::unique_ptr<PipelineVariants>,
                     PipelineKey::Hash,
                     PipelineKey::Equal>
      pipelines_;

  std::shared_ptr<Context> context_;

  bool is_valid_ = false;
  // A 1x1 opaque white texture that can be used as a placeholder binding.
  // Available for the lifetime of the scene context
  std::shared_ptr<Texture> placeholder_texture_;

  SceneContext(const SceneContext&) = delete;

  SceneContext& operator=(const SceneContext&) = delete;
};

}  // namespace scene
}  // namespace impeller
