/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#pragma once

#include "Base/ICloseable.hpp"
#include "InputKey.hpp"

namespace OpenVulkano::Input
{
	class InputDevice : public ICloseable
	{
		InputDeviceType deviceType = InputDeviceType::UNKNOWN;
		int index = -1;
		std::string name;
		float axisAsButtonThreshold = 0.5f;
		float buttonAsAxisValue = 1.0f;

	protected:
		InputDevice() = default;

		void Init(InputDeviceType type, int index, const std::string& name)
		{
			this->deviceType = type;
			this->index = index;
			this->name = name;
		}

		[[nodiscard]] virtual float ReadAxis(int16_t key) const = 0;

		[[nodiscard]] virtual bool ReadButton(int16_t key) const = 0;

		[[nodiscard]] virtual bool ReadButtonUp(int16_t key) const = 0;

		[[nodiscard]] virtual bool ReadButtonDown(int16_t key) const = 0;

	public:
		~InputDevice() override = default;

		virtual void Tick() {}

		void Close() override
		{
			this->deviceType = InputDeviceType::UNKNOWN;
			this->index = -1;
			this->name = "";
		}

		[[nodiscard]] InputDeviceType GetType() const { return deviceType; }
		[[nodiscard]] int GetIndex() const { return index; }
		[[nodiscard]] const std::string& GetName() const { return name; }

		[[nodiscard]] float GetAxisAsButtonThreshold() const { return axisAsButtonThreshold; }
		void SetAxisAsButtonThreshold(float value) { axisAsButtonThreshold = value; }

		[[nodiscard]] float GetButtonAsAxisValue() const { return buttonAsAxisValue; }
		void SetButtonAsAxisValue(float value) { buttonAsAxisValue = value; }

		[[nodiscard]] bool GetButton(InputKey key) const
		{
			if (key.GetInputDeviceType() != deviceType) return false;
			if (key.GetInputType() == InputKey::InputType::AXIS)
			{
				return ReadAxis(key.GetInputKey()) > axisAsButtonThreshold;
			}
			return ReadButton(key.GetInputKey());
		}

		[[nodiscard]] bool GetButtonUp(InputKey key) const
		{
			if (key.GetInputDeviceType() != deviceType) return false;
			if (key.GetInputType() == InputKey::InputType::AXIS)
			{
				//TODO handle
				return ReadAxis(key.GetInputKey()) > axisAsButtonThreshold;
			}
			return ReadButtonUp(key.GetInputKey());
		}

		[[nodiscard]] bool GetButtonDown(InputKey key) const
		{
			if (key.GetInputDeviceType() != deviceType) return false;
			if (key.GetInputType() == InputKey::InputType::AXIS)
			{
				//TODO handle
				return ReadAxis(key.GetInputKey()) > axisAsButtonThreshold;
			}
			return ReadButtonDown(key.GetInputKey());
		}

		[[nodiscard]] float GetAxis(InputKey key) const
		{
			if (key.GetInputDeviceType() != deviceType) return 0;
			if (key.GetInputType() == InputKey::InputType::BUTTON)
			{
				return ReadButton(key.GetInputKey()) ? buttonAsAxisValue : 0;
			}
			return ReadAxis(key.GetInputKey());
		}

		[[nodiscard]] float GetAxis(InputKey keyPositive, InputKey keyNegative) const
		{
			return GetAxis(keyPositive) - GetAxis(keyNegative);
		}
	};
}

