/*
 * Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
 */

#pragma once

#include <ox/std/memory.hpp>
#include <ox/fs/fs.hpp>

#include "clipboard.hpp"
#include "gfx.hpp"

namespace turbine {
class Context;

using TimeMs = uint64_t;
using UpdateHandler = int(*)(Context&);

enum Key {
	// GBA implementation currently relies on GamePad entry order
	GamePad_A = 0,
	GamePad_B,
	GamePad_Select,
	GamePad_Start,
	GamePad_Right,
	GamePad_Left,
	GamePad_Up,
	GamePad_Down,
	GamePad_R,
	GamePad_L,

	Num_0,
	Num_1,
	Num_2,
	Num_3,
	Num_4,
	Num_5,
	Num_6,
	Num_7,
	Num_8,
	Num_9,

	Alpha_A,
	Alpha_B,
	Alpha_C,
	Alpha_D,
	Alpha_E,
	Alpha_F,
	Alpha_G,
	Alpha_H,
	Alpha_I,
	Alpha_J,
	Alpha_K,
	Alpha_L,
	Alpha_M,
	Alpha_N,
	Alpha_O,
	Alpha_P,
	Alpha_Q,
	Alpha_R,
	Alpha_S,
	Alpha_T,
	Alpha_U,
	Alpha_V,
	Alpha_W,
	Alpha_X,
	Alpha_Y,
	Alpha_Z,

	Mod_Alt,
	Mod_Ctrl,
	Mod_Super,
	Mod_Shift,

	Escape,

	End
};

using KeyEventHandler = void(*)(Context&, Key, bool);
using MouseButtonEventHandler = void(*)(Context&, int btn, bool);

void setKeyEventHandler(Context &ctx, KeyEventHandler h) noexcept;

void setMouseButtonEventHandler(Context &ctx, MouseButtonEventHandler h) noexcept;

[[nodiscard]]
KeyEventHandler keyEventHandler(Context const &ctx) noexcept;

[[nodiscard]]
bool buttonDown(Context const &ctx, Key) noexcept;

ox::Result<ox::UPtr<Context>> init(
	ox::UPtr<ox::FileSystem> &&fs,
	ox::StringViewCR appName,
	ox::StringViewCR appId = {}) noexcept;

ox::Result<ox::UPtr<Context>> init(
	ox::StringViewCR fsPath,
	ox::StringViewCR appName,
	ox::StringViewCR appId = {}) noexcept;

ox::Error run(Context &ctx) noexcept;

// Returns the number of milliseconds that have passed since the start of the
// program.
[[nodiscard]]
TimeMs ticksMs(Context const &ctx) noexcept;

void requestShutdown(Context &ctx, bool force = false) noexcept;

using ShutdownHandler = bool (*)(Context&);

void setShutdownHandler(Context &ctx, ShutdownHandler handler) noexcept;

// Sets event handler that sleeps for the time given in the return value. The
// sleep time is a minimum of ~16 milliseconds.
void setUpdateHandler(Context &ctx, UpdateHandler) noexcept;

[[nodiscard]]
float scale(Context const &ctx) noexcept;

[[nodiscard]]
bool isWayland() noexcept;

}
