using System;
using System.Reflection;

using FMOD.Studio;
using FMODUnity;
using RobocraftX.Common.Audio;
using Unity.Mathematics;

namespace GamecraftModdingAPI.Utility
{
    public class Audio
    {
		private EventInstance sound;

		public Audio(string uri) : this(RuntimeManager.PathToGUID(uri))
		{
		}

		public Audio(Guid uri)
        {
            sound = RuntimeManager.CreateInstance(uri);
        }

        public static Audio Random()
		{
			System.Random potato = new System.Random();
			FieldInfo[] options = typeof(FMODAudioEvents).GetFields();
			Guid audio_uri;
            while (true)
			{
				int index = potato.Next(0, options.Length);
				try
				{
					audio_uri = (Guid)options[index].GetValue(null);
					break;
				}
				catch (InvalidCastException) { }
			}
			return new Audio(audio_uri);
		}

		public float this[string key]
		{
            get
			{
				sound.getParameterValue(key, out float val, out float finalVal);
				return val;
			}

			set => sound.setParameterValue(key, value);
		}

		public float this[int index]
        {
            get
            {
                sound.getParameterValueByIndex(index, out float val, out float finalVal);
                return val;
            }

            set => sound.setParameterValueByIndex(index, value);
        }

        public string[] Parameters
		{
			get
			{
				sound.getParameterCount(out int count);
				string[] parameters = new string[count];
				for (int i = 0; i < count; i++)
				{
					sound.getParameterByIndex(i, out ParameterInstance param);
					param.getDescription(out PARAMETER_DESCRIPTION desc);
					parameters[i] = desc.name;
				}
				return parameters;
			}
		}

		public float3 Position
		{
			get
			{
				sound.get3DAttributes(out FMOD.ATTRIBUTES_3D attr);
				return new float3(attr.position.x, attr.position.y, attr.position.z);
			}

			set => sound.set3DAttributes(RuntimeUtils.To3DAttributes(value));
		}

        public void Play()
		{
			sound.start();
		}

		public void Stop(FMOD.Studio.STOP_MODE mode = FMOD.Studio.STOP_MODE.IMMEDIATE)
		{
			sound.stop(mode);
		}

		~Audio() // Use the wannabe C++ destructor to destroy the C++ object
		{
			sound.release();
		}
    }
}