using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Dalamud.Hooking;
using Dalamud.Plugin.Services;
using OmicronMountMusicFixer;

public class BGMController
{
	public delegate void SongChangedHandler(int oldSong, int currentSong, int oldSecondSong, int secondSong);

	private unsafe delegate DisableRestart* AddDisableRestartIdPrototype(BGMScene* scene, ushort songId);

	private unsafe delegate int GetSpecialModeByScenePrototype(BGMPlayer* bgmPlayer);

	private const SceneFlags SceneZeroFlags = SceneFlags.Resume;

	private const int SceneCount = 12;

	private const int PlayersCount = 2;

	public SongChangedHandler OnSongChanged;

	private readonly AddDisableRestartIdPrototype _addDisableRestartId;

	private readonly Hook<GetSpecialModeByScenePrototype> _getSpecialModeForSceneHook;

	public int OldSongId { get; private set; }

	public int OldScene { get; private set; }

	public int CurrentSongId { get; private set; }

	public int CurrentScene { get; private set; }

	public int SecondSongId { get; private set; }

	public int SecondScene { get; private set; }

	public int OldSecondSongId { get; private set; }

	public int OldSecondScene { get; private set; }

	public int PlayingSongId { get; private set; }

	public int PlayingScene { get; private set; }

	public int CurrentAudibleSong
	{
		get
		{
			if (PlayingSongId != 0)
			{
				return PlayingSongId;
			}
			return CurrentSongId;
		}
	}

	public unsafe BGMController()
	{
		_addDisableRestartId = Marshal.GetDelegateForFunctionPointer<AddDisableRestartIdPrototype>(BGMAddressResolver.AddRestartId);
		_getSpecialModeForSceneHook = DalamudApi.Hooks.HookFromAddress<GetSpecialModeByScenePrototype>((IntPtr)BGMAddressResolver.GetSpecialMode, (GetSpecialModeByScenePrototype)GetSpecialModeBySceneDetour, (HookBackend)0);
		_getSpecialModeForSceneHook.Enable();
	}

	public void Dispose()
	{
		_getSpecialModeForSceneHook?.Disable();
		_getSpecialModeForSceneHook?.Dispose();
	}

	public void SetSpecialModeHandling(bool value)
	{
		if (value)
		{
			_getSpecialModeForSceneHook.Enable();
		}
		else
		{
			_getSpecialModeForSceneHook.Disable();
		}
	}

	public unsafe void Update()
	{
		ushort num = 0;
		ushort num2 = 0;
		int currentScene = 0;
		int secondScene = 0;
		if (BGMAddressResolver.BGMSceneList != IntPtr.Zero)
		{
			BGMScene* ptr = (BGMScene*)((IntPtr)BGMAddressResolver.BGMSceneList).ToPointer();
			for (int i = 0; i < 12; i++)
			{
				if (PlayingSongId != 0 && i == PlayingScene)
				{
					if (ptr[PlayingScene].BgmId != PlayingSongId)
					{
						SetSong((ushort)PlayingSongId, PlayingScene);
					}
				}
				else if (ptr[i].BgmReference != 0 && ptr[i].BgmId != 0 && ptr[i].BgmId != 9999)
				{
					if (num != 0)
					{
						num2 = ptr[i].BgmId;
						secondScene = i;
						break;
					}
					num = ptr[i].BgmId;
					currentScene = i;
				}
			}
		}
		int oldSong = 0;
		int currentSong = 0;
		int oldSecondSong = 0;
		int secondSong = 0;
		bool flag = false;
		bool flag2 = false;
		if (CurrentSongId != num)
		{
			OldSongId = CurrentSongId;
			OldScene = CurrentScene;
			CurrentSongId = num;
			CurrentScene = currentScene;
			flag = true;
			oldSong = OldSongId;
			currentSong = CurrentSongId;
		}
		if (SecondSongId != num2)
		{
			OldSecondSongId = SecondSongId;
			OldSecondScene = SecondScene;
			SecondSongId = num2;
			SecondScene = secondScene;
			flag2 = true;
			oldSecondSong = OldSecondSongId;
			secondSong = SecondSongId;
		}
		if (flag || flag2)
		{
			OnSongChanged?.Invoke(oldSong, currentSong, oldSecondSong, secondSong);
		}
	}

	public unsafe void SetSong(ushort songId, int priority = 0)
	{
		if ((priority < 0 || priority >= 12) ? true : false)
		{
			throw new IndexOutOfRangeException();
		}
		if ((songId != 0 && SongList.Instance.TryGetSong(songId, out var song) && !song.FileExists) || BGMAddressResolver.BGMSceneList == IntPtr.Zero)
		{
			return;
		}
		BGMScene* bgms = (BGMScene*)((IntPtr)BGMAddressResolver.BGMSceneList).ToPointer();
		bgms[priority].BgmReference = songId;
		bgms[priority].BgmId = songId;
		bgms[priority].PreviousBgmId = songId;
		if (songId == 0 && priority == 0)
		{
			bgms[priority].Flags = SceneFlags.Resume;
		}
		bgms[priority].Timer = 0f;
		bgms[priority].TimerEnable = 0;
		PlayingSongId = songId;
		PlayingScene = priority;
		if (SongList.Instance.IsDisableRestart(songId))
		{
			bgms[priority].Flags = SceneFlags.EnableDisableRestart;
			_addDisableRestartId(bgms + priority, songId);
			bgms[priority].Flags = SceneFlags.ForceAutoReset;
			Task.Delay(500).ContinueWith(delegate
			{
				bgms[priority].Flags = SceneFlags.ForceAutoReset | SceneFlags.EnableDisableRestart;
			});
		}
	}

	private unsafe int GetSpecialModeBySceneDetour(BGMPlayer* player)
	{
		if (player->BgmScene != PlayingScene || player->BgmId != PlayingSongId)
		{
			return _getSpecialModeForSceneHook.Original(player);
		}
		if (!SongList.Instance.TryGetSong(player->BgmId, out var song))
		{
			return _getSpecialModeForSceneHook.Original(player);
		}
		uint bgmScene = 10u;
		if (song.SpecialMode == 2)
		{
			bgmScene = 6u;
		}
		uint bgmScene2 = player->BgmScene;
		player->BgmScene = bgmScene;
		int result = _getSpecialModeForSceneHook.Original(player);
		player->BgmScene = bgmScene2;
		return result;
	}
}
