// 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.

#include "flutter/display_list/testing/dl_test_surface_metal.h"
#include "flutter/impeller/display_list/dl_dispatcher.h"
#include "flutter/impeller/display_list/dl_image_impeller.h"
#include "flutter/impeller/typographer/backends/skia/typographer_context_skia.h"

#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkSurface.h"

namespace flutter {
namespace testing {

class DlMetalSurfaceInstance : public DlSurfaceInstance {
 public:
  explicit DlMetalSurfaceInstance(
      std::unique_ptr<TestMetalSurface> metal_surface)
      : metal_surface_(std::move(metal_surface)) {}
  ~DlMetalSurfaceInstance() = default;

  sk_sp<SkSurface> sk_surface() const override {
    return metal_surface_->GetSurface();
  }

 private:
  std::unique_ptr<TestMetalSurface> metal_surface_;
};

bool DlMetalSurfaceProvider::InitializeSurface(size_t width,
                                               size_t height,
                                               PixelFormat format) {
  if (format != kN32PremulPixelFormat) {
    return false;
  }
  metal_context_ = std::make_unique<TestMetalContext>();
  metal_surface_ = MakeOffscreenSurface(width, height, format);
  return true;
}

std::shared_ptr<DlSurfaceInstance> DlMetalSurfaceProvider::GetPrimarySurface()
    const {
  if (!metal_surface_) {
    return nullptr;
  }
  return metal_surface_;
}

std::shared_ptr<DlSurfaceInstance> DlMetalSurfaceProvider::MakeOffscreenSurface(
    size_t width,
    size_t height,
    PixelFormat format) const {
  auto surface =
      TestMetalSurface::Create(*metal_context_, SkISize::Make(width, height));
  surface->GetSurface()->getCanvas()->clear(SK_ColorTRANSPARENT);
  return std::make_shared<DlMetalSurfaceInstance>(std::move(surface));
}

class DlMetalPixelData : public DlPixelData {
  using MetalScreenshot = impeller::testing::MetalScreenshot;

 public:
  explicit DlMetalPixelData(std::unique_ptr<MetalScreenshot> screenshot)
      : screenshot_(std::move(screenshot)),
        addr_(reinterpret_cast<const uint32_t*>(screenshot_->GetBytes())),
        ints_per_row_(screenshot_->GetBytesPerRow() / 4) {
    FML_DCHECK(screenshot_->GetBytesPerRow() == ints_per_row_ * 4);
  }
  ~DlMetalPixelData() override = default;

  const uint32_t* addr32(int x, int y) const override {
    return addr_ + (y * ints_per_row_) + x;
  }
  size_t width() const override { return screenshot_->GetWidth(); }
  size_t height() const override { return screenshot_->GetHeight(); }
  void write(const std::string& path) const override {
    screenshot_->WriteToPNG(path);
  }

 private:
  std::unique_ptr<MetalScreenshot> screenshot_;
  const uint32_t* addr_;
  const uint32_t ints_per_row_;
};

sk_sp<DlPixelData> DlMetalSurfaceProvider::ImpellerSnapshot(
    const sk_sp<DisplayList>& list,
    int width,
    int height) const {
  InitScreenShotter();
  impeller::DlDispatcher dispatcher;
  dispatcher.drawColor(flutter::DlColor::kTransparent(),
                       flutter::DlBlendMode::kSrc);
  list->Dispatch(dispatcher);
  auto picture = dispatcher.EndRecordingAsPicture();
  return sk_make_sp<DlMetalPixelData>(snapshotter_->MakeScreenshot(
      *aiks_context_, picture, {width, height}, false));
}

sk_sp<DlImage> DlMetalSurfaceProvider::MakeImpellerImage(
    const sk_sp<DisplayList>& list,
    int width,
    int height) const {
  InitScreenShotter();
  impeller::DlDispatcher dispatcher;
  dispatcher.drawColor(flutter::DlColor::kTransparent(),
                       flutter::DlBlendMode::kSrc);
  list->Dispatch(dispatcher);
  auto picture = dispatcher.EndRecordingAsPicture();
  std::shared_ptr<impeller::Image> image =
      picture.ToImage(*aiks_context_, {width, height});
  std::shared_ptr<impeller::Texture> texture = image->GetTexture();
  return impeller::DlImageImpeller::Make(texture);
}

void DlMetalSurfaceProvider::InitScreenShotter() const {
  if (!snapshotter_) {
    snapshotter_.reset(new MetalScreenshotter());
    auto typographer = impeller::TypographerContextSkia::Make();
    aiks_context_.reset(new impeller::AiksContext(
        snapshotter_->GetPlayground().GetContext(), typographer));
  }
}

}  // namespace testing
}  // namespace flutter
