/*
 * 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 "ArSessionArKit.h"
#include "Data/Concurent/MutexProtectedObject.hpp"
#include "Scene/Texture.hpp"
#include "Vulkan/Metal/MetalTextureCache.h"
#include <atomic>

#import <ARKit/ARSession.h>
#import <ARKit/ARConfiguration.h>

@class ArKitDelegate;

namespace OpenVulkano::AR::ArKit
{
	class ArSessionArKitInternal final : public ArSessionArKit, public std::enable_shared_from_this<ArSessionArKitInternal>
	{
	public:
		ArSessionArKitInternal(const ArSessionConfig& config);

		~ArSessionArKitInternal() override;

		void Start() override;

		void Stop() override;

		void Pause() override;

		[[nodiscard]] std::shared_ptr<ArFrame> GetFrame() override;

		void RequestHighResolutionFrame() override;
		
		size_t GetFrameId()
		{
			return m_frameId++;
		}

		// AR Kit delegate events
		void OnArNewFrame(ARSession* session, ARFrame* frame);
		void OnArSessionInterruptedChanged(ARSession* session, bool interrupted);
		void OnArSessionFailed(ARSession* session, NSError* error);
		void OnArCameraTrackingChange(ARSession* session, ARCamera* camera);
		void OnArAnchorsUpdate(NSArray<__kindof ARAnchor*>* anchors);
		bool ArShouldAttemptRelocalization();
		
		void SetRenderer(IRenderer* renderer) override;
		
		void LockExposureTime(bool locked) override;
		void LockWhitebalance(bool locked) override;
		void SetFlashlightOn(bool on) override;

	protected:
		Scene::Texture * MakeTexture(ArFrame *frame) override;

		void ReturnTexture(Scene::Texture *texture) override;

	private:
		ArKitDelegate* m_arKitDelegate;
		ARWorldTrackingConfiguration* m_arConfig;
		ARSession* m_arSession;
		Vulkan::MetalTextureCache m_textureCache;
/*#if (__cplusplus >= 202002L)
		std::atomic<std::shared_ptr<ArFrame>> m_frame;
#else*/
		SpintexProtectedObject<std::shared_ptr<ArFrame>> m_frame;
//#endif
		std::atomic_size_t m_frameId = 0;
		bool m_lockedConfiguration = false;
		bool m_lockedExposure = false;
		bool m_lockedWhitebalance = false;
	};
}
