// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: %{CURRENT_YEAR} %{AUTHOR} <%{EMAIL}>

#include "app.h"
#include <KSharedConfig>
#include <KWindowConfig>
#include <QQuickWindow>
#include <QTimer>

App::App()
    : m_global(std::make_unique<ColorManagementGlobal>())
{
}

App::~App()
{
}

void App::setPQ(QQuickWindow *window, int referenceLuminance)
{
    m_data[window] = {
        .mode = std::nullopt,
        .referenceLuminance = referenceLuminance,
    };
    doSetImageDescription(window);
}

void App::setImageDescription(QQuickWindow *window, int mode)
{
    m_data[window] = {
        .mode = mode,
        .referenceLuminance = 100,
    };
    doSetImageDescription(window);
}

QString App::preferredDescription() const
{
    const auto it = m_surfaces.find(m_mainWindow);
    if (it != m_surfaces.end()) {
        return it->second->m_feedback->m_preferred->info.m_description;
    } else {
        return QStringLiteral("unknown");
    }
}

void App::setMainWindow(QQuickWindow *window)
{
    m_mainWindow = window;
    // init the color management surface, so that the
    // preferred image description is read
    setImageDescription(window, 0);
}

void App::doSetImageDescription(QQuickWindow *window)
{
    const auto it = m_data.find(window);
    if (it == m_data.end()) {
        return;
    }
    auto waylandWindow = window->nativeInterface<QNativeInterface::Private::QWaylandWindow>();
    if (!waylandWindow) {
        window->installEventFilter(this);
        return;
    }
    auto &surface = m_surfaces[window];
    if (!surface) {
        auto feedback = std::make_unique<ColorManagementFeedback>(m_global->get_surface_feedback(waylandWindow->surface()));
        connect(feedback.get(), &ColorManagementFeedback::preferredChanged, this, &App::preferredChanged);
        surface = std::make_unique<ColorManagementSurface>(m_global.get(), window, m_global->get_surface(waylandWindow->surface()), std::move(feedback));
    }
    if (it->second.mode.has_value()) {
        surface->setImageDescriptionMode(*it->second.mode);
    } else {
        surface->setPQ(it->second.referenceLuminance);
    }
}

PendingImageDescription::PendingImageDescription(QQuickWindow *window, ColorManagementSurface *surface, ::wp_image_description_v1 *descr, uint32_t renderIntent)
    : QtWayland::wp_image_description_v1(descr)
    , m_window(window)
    , m_surface(surface)
    , m_renderIntent(renderIntent)
{
}

PendingImageDescription::~PendingImageDescription()
{
    wp_image_description_v1_destroy(object());
}

void PendingImageDescription::wp_image_description_v1_ready([[maybe_unused]] uint32_t identity)
{
    if (m_window && m_surface) {
        wp_color_management_surface_v1_set_image_description(m_surface->object(), object(), m_renderIntent);
        m_window->requestUpdate();
    }
    delete this;
}

bool App::eventFilter(QObject *watched, QEvent *event)
{
    auto window = qobject_cast<QQuickWindow *>(watched);
    if (!window) {
        return false;
    }
    if (event->type() == QEvent::PlatformSurface) {
        auto surfaceEvent = static_cast<QPlatformSurfaceEvent *>(event);
        if (surfaceEvent->surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated) {
            doSetImageDescription(window);
        }
    }
    return false;
}

void ColorManagementSurface::setImageDescriptionMode(int mode)
{
    // note that this is racy, unsetting the image description could
    // happen before a previously created image description is ready
    switch (mode) {
    case 0:
        unset_image_description();
        m_window->requestUpdate();
        break;
    case 1: {
        auto creator = m_global->create_parametric_creator();
        wp_image_description_creator_params_v1_set_primaries_named(creator, QtWayland::wp_color_manager_v1::primaries_srgb);
        wp_image_description_creator_params_v1_set_tf_named(creator, QtWayland::wp_color_manager_v1::transfer_function_gamma22);
        wp_image_description_creator_params_v1_set_luminances(creator, 0, 200, 100);
        wp_image_description_creator_params_v1_set_mastering_luminance(creator, 0, 200);
        new PendingImageDescription(m_window, this, wp_image_description_creator_params_v1_create(creator));
    } break;
    case 2: {
        auto creator = m_global->create_parametric_creator();
        wp_image_description_creator_params_v1_set_primaries_named(creator, QtWayland::wp_color_manager_v1::primaries_bt2020);
        wp_image_description_creator_params_v1_set_tf_named(creator, QtWayland::wp_color_manager_v1::transfer_function_gamma22);
        new PendingImageDescription(m_window, this, wp_image_description_creator_params_v1_create(creator));
    } break;
    case 3: {
        auto creator = m_global->create_parametric_creator();
        wp_image_description_creator_params_v1_set_primaries_named(creator, QtWayland::wp_color_manager_v1::primaries_bt2020);
        wp_image_description_creator_params_v1_set_tf_named(creator, QtWayland::wp_color_manager_v1::transfer_function_st2084_pq);
        new PendingImageDescription(m_window, this, wp_image_description_creator_params_v1_create(creator));
    } break;
    case 4: {
        auto creator = m_global->create_parametric_creator();
        wp_image_description_creator_params_v1_set_primaries_named(creator, QtWayland::wp_color_manager_v1::primaries_pal_m);
        wp_image_description_creator_params_v1_set_tf_named(creator, QtWayland::wp_color_manager_v1::transfer_function_gamma22);
        new PendingImageDescription(m_window, this, wp_image_description_creator_params_v1_create(creator));
    } break;
    case 5: {
        auto creator = m_global->create_parametric_creator();
        wp_image_description_creator_params_v1_set_primaries_named(creator, QtWayland::wp_color_manager_v1::primaries_cie1931_xyz);
        wp_image_description_creator_params_v1_set_tf_named(creator, QtWayland::wp_color_manager_v1::transfer_function_gamma22);
        new PendingImageDescription(m_window, this, wp_image_description_creator_params_v1_create(creator));
    } break;
    }
}

void ColorManagementSurface::setPQ(int referenceLuminance)
{
    auto creator = m_global->create_parametric_creator();
    wp_image_description_creator_params_v1_set_primaries_named(creator, QtWayland::wp_color_manager_v1::primaries_bt2020);
    wp_image_description_creator_params_v1_set_tf_named(creator, QtWayland::wp_color_manager_v1::transfer_function_st2084_pq);
    wp_image_description_creator_params_v1_set_luminances(creator, 0, 10'000, referenceLuminance);
    wp_image_description_creator_params_v1_set_mastering_luminance(creator, 0, 1'000);
    new PendingImageDescription(m_window, this, wp_image_description_creator_params_v1_create(creator));
}

#include "moc_app.cpp"
