#include "player.h"
#include "debug.h"
#include "game_world.h"

static inline
void InternalPlayerInitInput(Player* self) {
	// HORIZONTAL
	playerinput_add(self->input, CompositeAxis1D_as_InputAxis(compositeaxis1d_new(
		KeyBind_as_InputAxis(keybind_new(SDL_SCANCODE_A)),
		KeyBind_as_InputAxis(keybind_new(SDL_SCANCODE_D)),
		InputEvent_Float
	)), (InputDelegateFn)PlayerInputHorizontal);

	// VERTICAL
	playerinput_add(self->input, CompositeAxis1D_as_InputAxis(compositeaxis1d_new(
		KeyBind_as_InputAxis(keybind_new(SDL_SCANCODE_S)),
		KeyBind_as_InputAxis(keybind_new(SDL_SCANCODE_W)),
		InputEvent_Float
	)), (InputDelegateFn)PlayerInputVertical);
}

Player* MakePlayer() {
	Player* self = malloc(sizeof(Player));
	ASSERT_RETURN(self != NULL, NULL, "Could not allocate enough space for Player instance");

	Spritesheet* walk = spritesheet_load("assets/sprites/player/player_walk.png", IVectorFrom(512));
	Spritesheet* idle = spritesheet_load("assets/sprites/player/player_walk.png", IVectorFrom(512));

	*self = (Player){
		.transform = IdentityTransform,

		.input = playerinput_new(self, -1),
		.input_direction = ZeroVector,

		.faceDirection = 0,
		
		.animationStateMachine = state_machine_init(self, PlayerIdle()),
		.animFrame = 0,
		.animFrameInterval = 1.0f / 4.0f,
		.animFrameTimer = 0.0f,
		
		.stand = idle,
		.walk = walk,

		.sprite = sprite_from_spritesheet(walk, 0),
	};

	return self;
}

Player* SpawnPlayer(Vector location) {
	Player* self = MakePlayer();
	self->transform.position = location;
	game_world_add_entity(Player_as_BehaviourEntity(self));
	return self;
}

void PlayerStart(Player* self) {}

void PlayerUpdate(Player* self, float deltaTime) {
	state_machine_update(self->animationStateMachine, deltaTime);
}

void PlayerDestroy(Player* self) {
	state_machine_destroy(self->animationStateMachine);
	spritesheet_destroy(self->walk);
	spritesheet_destroy(self->stand);
	sprite_destroy(self->sprite);
}

void PlayerDraw(Player* self) {
	sprite_entity_draw(Player_as_SpriteEntity(self));
}

void PlayerInputHorizontal(Player* self, InputEvent event) {}

void PlayerInputVertical(Player* self, InputEvent event) {}

Sprite* PlayerGetSprite(Player* self) {
	return self->sprite;
}

Transform* PlayerGetTransform(Player* self) {
	return &self->transform;
}

const State* PlayerAnimationUpdate(Player* self, float deltaTime) {
	self->animFrameTimer += deltaTime;

	if (self->animFrameTimer > self->animFrameInterval) {
		self->animFrameTimer = 0.f;
		++self->animFrame;
		size_t nextFrame = self->animFrame * 8 + self->faceDirection;
		sprite_set_tile(self->sprite, nextFrame);
	}

	return state_machine_get_current_state(self->animationStateMachine);
}

void PlayerAnimationExit(Player* self) {}

void PlayerIdleEnter(Player* self) {
	self->sprite = sprite_from_spritesheet(self->stand, 0);
}

const State* PlayerIdleUpdate(Player* self, float deltaTime) {
	PlayerAnimationUpdate(self, deltaTime);
	return PlayerIdle();
}
