#pragma once

#include "Emu/Memory/vm_ptr.h"
#include "Emu/Cell/ErrorCodes.h"
#include "cellSearch.h"

// Error Codes
enum CellMusicError : u32
{
	CELL_MUSIC_CANCELED = 1,
	CELL_MUSIC_PLAYBACK_FINISHED = 0x8002c101,
	CELL_MUSIC_ERROR_PARAM = 0x8002c102,
	CELL_MUSIC_ERROR_BUSY = 0x8002c103,
	CELL_MUSIC_ERROR_NO_ACTIVE_CONTENT = 0x8002c104,
	CELL_MUSIC_ERROR_NO_MATCH_FOUND = 0x8002c105,
	CELL_MUSIC_ERROR_INVALID_CONTEXT = 0x8002c106,
	CELL_MUSIC_ERROR_PLAYBACK_FAILURE = 0x8002c107,
	CELL_MUSIC_ERROR_NO_MORE_CONTENT = 0x8002c108,
	CELL_MUSIC_DIALOG_OPEN = 0x8002c109,
	CELL_MUSIC_DIALOG_CLOSE = 0x8002c10a,
	CELL_MUSIC_ERROR_GENERIC = 0x8002c1ff,
};

enum CellMusic2Error : u32
{
	CELL_MUSIC2_CANCELED = 1,
	CELL_MUSIC2_PLAYBACK_FINISHED = 0x8002c101,
	CELL_MUSIC2_ERROR_PARAM = 0x8002c102,
	CELL_MUSIC2_ERROR_BUSY = 0x8002c103,
	CELL_MUSIC2_ERROR_NO_ACTIVE_CONTENT = 0x8002c104,
	CELL_MUSIC2_ERROR_NO_MATCH_FOUND = 0x8002c105,
	CELL_MUSIC2_ERROR_INVALID_CONTEXT = 0x8002c106,
	CELL_MUSIC2_ERROR_PLAYBACK_FAILURE = 0x8002c107,
	CELL_MUSIC2_ERROR_NO_MORE_CONTENT = 0x8002c108,
	CELL_MUSIC2_DIALOG_OPEN = 0x8002c109,
	CELL_MUSIC2_DIALOG_CLOSE = 0x8002c10a,
	CELL_MUSIC2_ERROR_GENERIC = 0x8002c1ff,
};

enum
{
	CELL_SYSUTIL_MUSIC_INITIALIZING_FINISHED = 1,
	CELL_SYSUTIL_MUSIC_SHUTDOWN_FINISHED = 4, // Was 3 in 1.03, changed to 4 in 1.1
	CELL_SYSUTIL_MUSIC_LOADING_FINISHED = 5,
	CELL_SYSUTIL_MUSIC_UNLOADING_FINISHED = 7,
	CELL_SYSUTIL_MUSIC_RELEASED = 9,
	CELL_SYSUTIL_MUSIC_GRABBED = 11,
};

enum
{
	CELL_SYSUTIL_MUSIC2_INITIALIZING_FINISHED = CELL_SYSUTIL_MUSIC_INITIALIZING_FINISHED,
	CELL_SYSUTIL_MUSIC2_SHUTDOWN_FINISHED = CELL_SYSUTIL_MUSIC_SHUTDOWN_FINISHED,
	CELL_SYSUTIL_MUSIC2_LOADING_FINISHED = CELL_SYSUTIL_MUSIC_LOADING_FINISHED,
	CELL_SYSUTIL_MUSIC2_UNLOADING_FINISHED = CELL_SYSUTIL_MUSIC_UNLOADING_FINISHED,
	CELL_SYSUTIL_MUSIC2_RELEASED = CELL_SYSUTIL_MUSIC_RELEASED,
	CELL_SYSUTIL_MUSIC2_GRABBED = CELL_SYSUTIL_MUSIC_GRABBED,
};

enum
{
	CELL_MUSIC_EVENT_STATUS_NOTIFICATION = 0,
	CELL_MUSIC_EVENT_INITIALIZE_RESULT = 1,
	CELL_MUSIC_EVENT_FINALIZE_RESULT = 2,
	CELL_MUSIC_EVENT_SELECT_CONTENTS_RESULT = 3,
	CELL_MUSIC_EVENT_SET_PLAYBACK_COMMAND_RESULT = 4,
	CELL_MUSIC_EVENT_SET_VOLUME_RESULT = 5,
	CELL_MUSIC_EVENT_SET_SELECTION_CONTEXT_RESULT = 6,
	CELL_MUSIC_EVENT_UI_NOTIFICATION = 7,
};

enum
{
	CELL_MUSIC2_EVENT_STATUS_NOTIFICATION = CELL_MUSIC_EVENT_STATUS_NOTIFICATION,
	CELL_MUSIC2_EVENT_INITIALIZE_RESULT = CELL_MUSIC_EVENT_INITIALIZE_RESULT,
	CELL_MUSIC2_EVENT_FINALIZE_RESULT = CELL_MUSIC_EVENT_FINALIZE_RESULT,
	CELL_MUSIC2_EVENT_SELECT_CONTENTS_RESULT = CELL_MUSIC_EVENT_SELECT_CONTENTS_RESULT,
	CELL_MUSIC2_EVENT_SET_PLAYBACK_COMMAND_RESULT = CELL_MUSIC_EVENT_SET_PLAYBACK_COMMAND_RESULT,
	CELL_MUSIC2_EVENT_SET_VOLUME_RESULT = CELL_MUSIC_EVENT_SET_VOLUME_RESULT,
	CELL_MUSIC2_EVENT_SET_SELECTION_CONTEXT_RESULT = CELL_MUSIC_EVENT_SET_SELECTION_CONTEXT_RESULT,
	CELL_MUSIC2_EVENT_UI_NOTIFICATION = CELL_MUSIC_EVENT_UI_NOTIFICATION,
};

enum
{
	CELL_MUSIC_PB_CMD_STOP = 0,
	CELL_MUSIC_PB_CMD_PLAY = 1,
	CELL_MUSIC_PB_CMD_PAUSE = 2,
	CELL_MUSIC_PB_CMD_NEXT = 3,
	CELL_MUSIC_PB_CMD_PREV = 4,
	CELL_MUSIC_PB_CMD_FASTFORWARD = 5,
	CELL_MUSIC_PB_CMD_FASTREVERSE = 6,
};

enum
{
	CELL_MUSIC2_PB_CMD_STOP = CELL_MUSIC_PB_CMD_STOP,
	CELL_MUSIC2_PB_CMD_PLAY = CELL_MUSIC_PB_CMD_PLAY,
	CELL_MUSIC2_PB_CMD_PAUSE = CELL_MUSIC_PB_CMD_PAUSE,
	CELL_MUSIC2_PB_CMD_NEXT = CELL_MUSIC_PB_CMD_NEXT,
	CELL_MUSIC2_PB_CMD_PREV = CELL_MUSIC_PB_CMD_PREV,
	CELL_MUSIC2_PB_CMD_FASTFORWARD = CELL_MUSIC_PB_CMD_FASTFORWARD,
	CELL_MUSIC2_PB_CMD_FASTREVERSE = CELL_MUSIC_PB_CMD_FASTREVERSE,
};

enum
{
	CELL_MUSIC_PB_STATUS_STOP = 0,
	CELL_MUSIC_PB_STATUS_PLAY = 1,
	CELL_MUSIC_PB_STATUS_PAUSE = 2,
	CELL_MUSIC_PB_STATUS_FASTFORWARD = 3,
	CELL_MUSIC_PB_STATUS_FASTREVERSE = 4,
};

enum
{
	CELL_MUSIC2_PB_STATUS_STOP = CELL_MUSIC_PB_STATUS_STOP,
	CELL_MUSIC2_PB_STATUS_PLAY = CELL_MUSIC_PB_STATUS_PLAY,
	CELL_MUSIC2_PB_STATUS_PAUSE = CELL_MUSIC_PB_STATUS_PAUSE,
	CELL_MUSIC2_PB_STATUS_FASTFORWARD = CELL_MUSIC_PB_STATUS_FASTFORWARD,
	CELL_MUSIC2_PB_STATUS_FASTREVERSE = CELL_MUSIC_PB_STATUS_FASTREVERSE,
};

enum
{
	CELL_MUSIC_PLAYBACK_MEMORY_CONTAINER_SIZE = 11 * 1024 * 1024,
	CELL_MUSIC_PLAYER_MODE_NORMAL = 0,
	CELL_MUSIC2_PLAYER_MODE_NORMAL = CELL_MUSIC_PLAYER_MODE_NORMAL,
	CELL_MUSIC_SELECTION_CONTEXT_SIZE = 2048,
};

using CellMusicCallback = void(u32 event, vm::ptr<void> param, vm::ptr<void> userData);
using CellMusic2Callback = void(u32 event, vm::ptr<void> param, vm::ptr<void> userData);

struct CellMusicSelectionContext
{
	// TODO: find out what fw does with it
	// Let's just hijack it with our own data.
	char data[CELL_MUSIC_SELECTION_CONTEXT_SIZE];
};

struct music_selection_context
{
	bool valid = false;
	char magic[4] = "SUS";
	std::string hash;
	CellSearchContentType content_type = CELL_SEARCH_CONTENTTYPE_MUSIC;
	CellSearchRepeatMode repeat_mode = CELL_SEARCH_REPEATMODE_NONE;
	CellSearchContextOption context_option = CELL_SEARCH_CONTEXTOPTION_NONE;
	u32 first_track{0};
	u32 current_track{0};
	std::vector<std::string> playlist;

	static constexpr u32 max_depth = 2; // root + 1 folder + file
	static constexpr const char* target_file_type = "Music Playlist";
	static constexpr const char* target_version = "1.0";
	static std::string get_next_hash();
	static std::string context_to_hex(const CellMusicSelectionContext& context);

	bool set(const CellMusicSelectionContext& in);
	CellMusicSelectionContext get() const;

	std::string to_string() const;
	std::string get_yaml_path() const;

	void set_playlist(const std::string& path);
	void create_playlist(const std::string& new_hash);
	bool load_playlist();
	void set_track(std::string_view track);
	u32 step_track(bool next);

	operator bool() const
	{
		return atomic_storage<bool>::load(valid);
	}

	// Helper
	error_code find_content_id(vm::ptr<CellSearchContentId> contents_id);
};
