#pragma once

#include "foundation/result.h"

#include <cstddef>
#include <span>

namespace pp::app {

enum class InterfaceDirection {
    left_to_right,
    right_to_left,
};

enum class TimelapseRecordingAction {
    no_op,
    start_recording,
    stop_recording,
};

struct ScaleApplicationPlan {
    float scale = 1.0F;
    float display_density = 1.0F;
    float font_scale = 1.0F;
};

struct ScaleOptionSelection {
    bool has_selection = false;
    std::size_t index = 0;
};

struct InterfaceDirectionPlan {
    InterfaceDirection direction = InterfaceDirection::left_to_right;
};

struct TimelapsePreferencePlan {
    bool enabled = true;
    TimelapseRecordingAction recording_action = TimelapseRecordingAction::no_op;
};

struct StoredIntegerPreferencePlan {
    int value = 0;
};

struct StoredBooleanPreferencePlan {
    bool value = false;
};

class AppPreferenceServices {
public:
    virtual ~AppPreferenceServices() = default;

    virtual void apply_ui_scale(const ScaleApplicationPlan& plan) = 0;
    virtual void apply_viewport_scale(const ScaleApplicationPlan& plan) = 0;
    virtual void apply_interface_direction(const InterfaceDirectionPlan& plan) = 0;
    virtual bool apply_vr_mode_preference(const StoredBooleanPreferencePlan& plan) = 0;
    virtual void apply_vr_controllers_preference(const StoredBooleanPreferencePlan& plan) = 0;
    virtual void apply_timelapse_preference(const TimelapsePreferencePlan& plan) = 0;
    virtual void apply_canvas_cursor_mode(const StoredIntegerPreferencePlan& plan) = 0;
};

[[nodiscard]] constexpr ScaleApplicationPlan plan_ui_scale(
    float requested_scale,
    float display_density) noexcept
{
    return {
        requested_scale,
        display_density,
        requested_scale * display_density,
    };
}

[[nodiscard]] constexpr ScaleApplicationPlan plan_viewport_scale(
    float requested_scale,
    float display_density = 1.0F) noexcept
{
    return {
        requested_scale,
        display_density,
        requested_scale * display_density,
    };
}

[[nodiscard]] constexpr ScaleOptionSelection plan_scale_option_selection(
    float current_scale,
    std::span<const float> options) noexcept
{
    ScaleOptionSelection selection;
    for (std::size_t index = 0; index < options.size(); ++index) {
        if (current_scale >= options[index]) {
            selection.has_selection = true;
            selection.index = index;
        }
    }
    return selection;
}

[[nodiscard]] constexpr InterfaceDirectionPlan plan_interface_direction(bool right_to_left) noexcept
{
    return {
        right_to_left ? InterfaceDirection::right_to_left : InterfaceDirection::left_to_right,
    };
}

[[nodiscard]] constexpr TimelapsePreferencePlan plan_timelapse_preference(
    bool enabled,
    bool recording_running) noexcept
{
    if (enabled && !recording_running) {
        return { enabled, TimelapseRecordingAction::start_recording };
    }
    if (!enabled && recording_running) {
        return { enabled, TimelapseRecordingAction::stop_recording };
    }
    return { enabled, TimelapseRecordingAction::no_op };
}

[[nodiscard]] constexpr StoredBooleanPreferencePlan plan_vr_controllers_preference(
    bool enabled) noexcept
{
    return { enabled };
}

[[nodiscard]] constexpr StoredBooleanPreferencePlan plan_vr_mode_preference(bool enabled) noexcept
{
    return { enabled };
}

[[nodiscard]] constexpr StoredIntegerPreferencePlan plan_canvas_cursor_mode(int mode) noexcept
{
    return { mode };
}

[[nodiscard]] inline pp::foundation::Status execute_ui_scale_preference(
    float requested_scale,
    float display_density,
    AppPreferenceServices& services)
{
    services.apply_ui_scale(plan_ui_scale(requested_scale, display_density));
    return pp::foundation::Status::success();
}

[[nodiscard]] inline pp::foundation::Status execute_viewport_scale_preference(
    float requested_scale,
    float display_density,
    AppPreferenceServices& services)
{
    services.apply_viewport_scale(plan_viewport_scale(requested_scale, display_density));
    return pp::foundation::Status::success();
}

[[nodiscard]] inline pp::foundation::Status execute_interface_direction_preference(
    bool right_to_left,
    AppPreferenceServices& services)
{
    services.apply_interface_direction(plan_interface_direction(right_to_left));
    return pp::foundation::Status::success();
}

[[nodiscard]] inline pp::foundation::Status execute_vr_mode_preference(
    bool enabled,
    AppPreferenceServices& services)
{
    if (!services.apply_vr_mode_preference(plan_vr_mode_preference(enabled))) {
        return pp::foundation::Status::invalid_argument("VR mode could not start");
    }
    return pp::foundation::Status::success();
}

[[nodiscard]] inline pp::foundation::Status execute_vr_controllers_preference(
    bool enabled,
    AppPreferenceServices& services)
{
    services.apply_vr_controllers_preference(plan_vr_controllers_preference(enabled));
    return pp::foundation::Status::success();
}

[[nodiscard]] inline pp::foundation::Status execute_timelapse_preference(
    bool enabled,
    bool recording_running,
    AppPreferenceServices& services)
{
    services.apply_timelapse_preference(plan_timelapse_preference(enabled, recording_running));
    return pp::foundation::Status::success();
}

[[nodiscard]] inline pp::foundation::Status execute_canvas_cursor_mode_preference(
    int mode,
    AppPreferenceServices& services)
{
    services.apply_canvas_cursor_mode(plan_canvas_cursor_mode(mode));
    return pp::foundation::Status::success();
}

}
