/*
 * Copyright 2024 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "tests/Test.h"

#include "include/core/SkCanvas.h"
#include "include/gpu/graphite/BackendTexture.h"
#include "include/gpu/graphite/Context.h"
#include "include/gpu/graphite/Image.h"
#include "include/gpu/graphite/Recorder.h"
#include "include/gpu/graphite/Surface.h"
#include "src/core/SkAutoPixmapStorage.h"
#include "src/gpu/graphite/Caps.h"
#include "src/gpu/graphite/ContextPriv.h"
#include "tools/gpu/ManagedBackendTexture.h"
#include "tools/graphite/GraphiteTestContext.h"

using namespace skgpu;
using namespace skgpu::graphite;

DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ImageWrapTextureMipmapsTest,
                                               reporter,
                                               context,
                                               testContext,
                                               true,
                                               CtsEnforcement::kApiLevel_202404) {
    auto recorder = context->makeRecorder();
    if (!recorder) {
        ERRORF(reporter, "Could not make recorder");
        return;
    }

    skgpu::Protected isProtected = skgpu::Protected(context->priv().caps()->protectedSupport());

    auto info = SkImageInfo::Make({2, 1}, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
    SkAutoPixmapStorage basePM, topPM;
    basePM.alloc(info);
    basePM.erase(SK_ColorGREEN);
    topPM.alloc(info.makeDimensions({1, 1}));
    topPM.erase(SK_ColorBLUE);

    SkPixmap levelPMs[]{basePM, topPM};
    auto mbet = sk_gpu_test::ManagedGraphiteTexture::MakeMipmappedFromPixmaps(recorder.get(),
                                                                              levelPMs,
                                                                              Renderable::kNo,
                                                                              isProtected);

    if (!mbet) {
        ERRORF(reporter, "Could not make backend texture");
        return;
    }

    std::unique_ptr<Recording> recording = recorder->snap();

    auto recordingFinishProc = [](void* context, CallbackResult) {
        std::unique_ptr<Recording>(static_cast<Recording*>(context));
    };

    skgpu::graphite::InsertRecordingInfo recordingInfo;
    recordingInfo.fFinishedProc = recordingFinishProc;
    recordingInfo.fRecording = recording.get();
    recordingInfo.fFinishedContext = recording.release();
    if (!context->insertRecording(recordingInfo)) {
        ERRORF(reporter, "Could not insert recording");
        return;
    }

    static constexpr struct TestCase {
        SkImages::GenerateMipmapsFromBase genMipmaps;
        SkColor expectedColor;
    } kTestCases[]{{SkImages::GenerateMipmapsFromBase::kNo , 0xFFFF0000},
                   {SkImages::GenerateMipmapsFromBase::kYes, 0XFF00FF00}};

    for (const auto& testCase : kTestCases) {
        recorder = context->makeRecorder();
        if (!recorder) {
            ERRORF(reporter, "Could not make recorder");
            return;
        }

        auto image = SkImages::WrapTexture(recorder.get(),
                                           mbet->texture(),
                                           info.alphaType(),
                                           info.refColorSpace(),
                                           Origin::kTopLeft,
                                           testCase.genMipmaps,
                                           sk_gpu_test::ManagedGraphiteTexture::ImageReleaseProc,
                                           mbet->releaseContext());
        if (!recorder) {
            ERRORF(reporter, "Could not make image");
            return;
        }

        // We determe the contents of the image's top level by doing a downsampling draw to a
        // surface and then reading the surface's contents.
        auto surface = SkSurfaces::RenderTarget(recorder.get(), info.makeDimensions({1, 1}));
        if (!recorder) {
            ERRORF(reporter, "Could not make surface");
            return;
        }

        auto shader = image->makeShader(
                SkTileMode::kRepeat,
                SkTileMode::kRepeat,
                SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNearest));

        surface->getCanvas()->scale(0.05f, 0.05f);
        SkPaint paint;
        paint.setShader(std::move(shader));
        surface->getCanvas()->drawPaint(paint);

        recording = recorder->snap();
        recordingInfo.fRecording = recording.get();
        recordingInfo.fFinishedContext = recording.release();
        if (!context->insertRecording(recordingInfo)) {
            ERRORF(reporter, "Could not insert recording");
            return;
        }

        struct ReadContext {
            bool called = false;
            bool success = false;
            uint32_t color;
        };
        auto readPixelsCallback = [](SkImage::ReadPixelsContext context,
                                     std::unique_ptr<const SkImage::AsyncReadResult> result) {
            auto& readContext = *static_cast<ReadContext*>(context);
            readContext.called = true;
            if (result) {
                readContext.success = true;
                readContext.color = *static_cast<const uint32_t*>(result->data(0));
            }
        };
        ReadContext readContext;
        context->asyncRescaleAndReadPixels(surface.get(),
                                           surface->imageInfo(),
                                           SkIRect::MakeSize(surface->imageInfo().dimensions()),
                                           SkImage::RescaleGamma::kSrc,
                                           SkImage::RescaleMode::kNearest,
                                           readPixelsCallback,
                                           &readContext);
        context->submit();
        while (!readContext.called) {
            testContext->tick();
            context->checkAsyncWorkCompletion();
        }

        if (!readContext.success) {
            ERRORF(reporter, "Read pixels failed");
            return;
        }

        REPORTER_ASSERT(reporter, readContext.color == testCase.expectedColor);
    }
}
